diff --git a/apps/docs/AGENTS.md b/apps/docs/AGENTS.md new file mode 120000 index 0000000000..681311eb9c --- /dev/null +++ b/apps/docs/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/apps/docs/CLAUDE.md b/apps/docs/CLAUDE.md new file mode 100644 index 0000000000..e96b6fea25 --- /dev/null +++ b/apps/docs/CLAUDE.md @@ -0,0 +1,105 @@ +# SuperDoc Documentation + +Mintlify-powered docs at `docs.superdoc.dev`. + +## File structure + +File paths must mirror the navigation structure in `docs.json`. If a page appears under "Guides > Collaboration" in the nav, the file lives in `guides/collaboration/`, not somewhere else. + +When moving or renaming a page, always add a redirect in `docs.json`: + +```json +{ + "source": "/old/path", + "destination": "/new/path" +} +``` + +## Brand voice + +One personality, two registers. SuperDoc is the same person in every conversation — warm, clear, technically confident. It adjusts **what it emphasizes** based on who's listening. Developers hear about the how. Leaders hear about the why. + +Documentation uses the **developer register**: clear, direct, code-forward. Respect the reader's time. + +### Headings + +Sentence case, always. "What we built" not "What We Built." + +### Universal voice rules + +- **Say what it does, not what it is** — "Renders DOCX files in the browser" not "an enterprise document management solution." Nouns are vague. Verbs are clear. +- **Short sentences win** — If a sentence has a comma, try splitting it in two. If it has a semicolon, definitely split it. Scannable beats comprehensive. +- **No buzzwords** — "Next-generation," "cutting-edge," "revolutionary," "best-in-class" are banned. If it sounds like a press release, rewrite it. +- **Show, then tell** — A code snippet or demo is always better than a paragraph of description. When words are needed, be specific: "5 lines" not "easy." +- **"You" not "we"** — "Your documents stay on your servers" hits harder than "We ensure data privacy." The reader is the hero, not SuperDoc. +- **Acknowledge trade-offs** — If something has a limitation, say so. "SuperDoc runs client-side, so very large documents (1000+ pages) need good hardware." Honesty builds trust. +- **Be specific with numbers** — "60+ extensions" not "many extensions." "5 lines of code" not "minimal integration." Specificity is credibility. +- **Conversational, not chummy** — Write like you're talking to a smart colleague. Not a pitch deck ("leverage synergies") and not a chat message ("lol it just works fr fr"). + +### Developer register pattern + +**Structure:** What it does → How to use it → What it saves you + +Lead with the developer's problem or goal. Follow with what SuperDoc does (concretely). End with how fast they can start. Always include code or an install command near the top. + +Example: +> "Add document signing to your app with the esign package. Drop in the component, define your fields, and get back a signed document with a full audit trail. No need to integrate DocuSign or build signing from scratch." + +### Same concept, two registers + +| Concept | Developer register | Leader register | +|---|---|---| +| Self-hosted | "Runs entirely in the browser. No cloud calls. Your data stays on your servers." | "Documents never leave your infrastructure. Full data sovereignty with zero cloud dependency." | +| Easy to use | "Five lines of code. Pass a file, mount the editor, done." | "Your team can ship document editing in days, not quarters. No specialized hires needed." | +| DOCX fidelity | "Built on OOXML. Real pagination, section breaks, headers/footers. Not rich text with export bolted on." | "Users see documents exactly as they look in Word. No formatting loss, no complaints, no re-work." | +| Collaboration | "Yjs-based CRDT. Add real-time editing in ~10 lines. Conflicts resolve automatically." | "Teams edit documents together in real time. Built-in conflict resolution means no lost work." | +| Open source | "AGPLv3. Read the code, fork it, contribute. Commercial license if you need proprietary." | "Open-source foundation means no vendor lock-in. Inspect the code. Switch away anytime." | +| Extensible | "60+ extensions built-in. Write your own with the plugin API. Full ProseMirror access." | "Adapts to your workflow, not the other way around. Custom extensions, branding, and integrations." | +| AI | "Bring your own LLM. AI actions with tool use — find, replace, highlight, insert. Streaming built in." | "AI-assisted document workflows with your choice of provider. Your data, your model, your infrastructure." | + +### Quick reference + +| Instead of | Write | Why | +|---|---|---| +| "Next-generation document editor" | "A document editor for the web" | Cut the hype. Say what it is. | +| "Seamless integration" | "Five lines of code" | Specific beats vague. | +| "Enterprise-grade security" | "Self-hosted. Your documents never leave your servers." | Describe the mechanism, not the claim. | +| "Leveraging AI capabilities" | "AI that finds, replaces, and rewrites text in your documents" | Say what it does. | +| "Robust collaboration features" | "Real-time editing with Yjs. Conflicts resolve automatically." | Name the tech. Devs trust specifics. | +| "We ensure data privacy" | "Your documents stay on your servers" | "You" framing. Mechanism, not promise. | +| "Comprehensive formatting support" | "60+ extensions: tables, images, lists, tracked changes, and more" | List beats adjective. | +| "Get in touch for pricing" | "Free under AGPLv3. Commercial license starts at $X/year." | Transparency builds trust. Devs hate hidden pricing. | + +## Page depth + +- **Getting Started** pages are high-level overviews. Link to detailed pages, don't duplicate content. +- **Core** pages (SuperDoc, SuperEditor) are the detailed API reference. +- **Module** pages document configuration, API, and events for each module. +- **Guide** pages are step-by-step walkthroughs for specific integrations. + +Don't add Tips, Warnings, or deep explanations in overview pages. Keep examples concise. + +## API naming + +- `superdoc.export()` for SuperDoc-level methods +- `superdoc.activeEditor.commands.X()` for editor commands +- `superdoc.activeEditor.getHTML()` for editor-level methods +- `superdoc.getHTML()` returns `Array` (one per document section) + +Always verify API names against the source code before documenting. Key source files: + +| API surface | Source | +|---|---| +| SuperDoc methods | `packages/superdoc/src/core/SuperDoc.js` | +| SuperDoc config | `packages/superdoc/src/core/types/index.js` | +| Editor methods | `packages/super-editor/src/core/Editor.ts` | +| Extensions | `packages/super-editor/src/extensions/` | + +## Mintlify components + +Common components: `ParamField`, `Note`, `Warning`, `Tip`, `CardGroup`, `Card`, `Tabs`, `Tab`, `Info`. + +## Commands + +- `npx mintlify dev` — Start local dev server +- `npx mintlify broken-links` — Check for broken links diff --git a/apps/docs/ai/ai-actions/methods.mdx b/apps/docs/ai/ai-actions/methods.mdx index 245a4164aa..3071afde8a 100644 --- a/apps/docs/ai/ai-actions/methods.mdx +++ b/apps/docs/ai/ai-actions/methods.mdx @@ -608,7 +608,7 @@ if (isValidTool(myTool)) { } ``` -## Advanced Exports +## Advanced exports For advanced use cases, the package exports additional classes and utilities: diff --git a/apps/docs/ai/ai-actions/overview.mdx b/apps/docs/ai/ai-actions/overview.mdx index 3bf8c6c8cc..39d27d09e3 100644 --- a/apps/docs/ai/ai-actions/overview.mdx +++ b/apps/docs/ai/ai-actions/overview.mdx @@ -51,7 +51,7 @@ await ai.action.replace( Formatting results depend on the source DOCX styles; list indentation may vary and may require follow-up instructions. -## What it is +## What it does AI Actions is SuperDoc's **high-level AI offering**. It provides pre-built operations for common document automation tasks: @@ -107,11 +107,11 @@ try { Enable verbose logging by setting `enableLogging: true`. The package will emit parsing and traversal issues to `console.error`. -## Advanced Exports +## Advanced exports The package exports additional utilities for advanced use cases: -### Provider Factory +### Provider factory ```ts import { createAIProvider } from '@superdoc-dev/ai'; @@ -140,14 +140,14 @@ const ai = new AIActions(superdoc, { user, provider }); const result = await ai.planner.execute('Review the document and add comments to all legal terms'); ``` -### Service Classes +### Service classes For custom implementations, you can use the lower-level service classes: - **`AIActionsService`** - Core service class that provides AI-powered document actions - **`EditorAdapter`** - Adapter for SuperDoc editor operations, encapsulating editor-specific API calls -### Tool Utilities +### Tool utilities Utilities for working with AI tools: @@ -166,9 +166,9 @@ const myTool = { const isValid = isValidTool(myTool); ``` -### Type Exports +### Type exports -The package exports comprehensive TypeScript types including: +The package exports TypeScript types including: - `AIPlannerConfig`, `AIPlannerExecutionResult`, `AIPlan` - Planner types - `AIToolActions`, `SelectionRange`, `SelectionSnapshot` - Tool and selection types - `AIProviderInput`, `OpenAIProviderConfig`, `AnthropicProviderConfig`, `HttpProviderConfig` - Provider configuration types diff --git a/apps/docs/ai/ai-builder/overview.mdx b/apps/docs/ai/ai-builder/overview.mdx index f7333223b7..d9928a00c8 100644 --- a/apps/docs/ai/ai-builder/overview.mdx +++ b/apps/docs/ai/ai-builder/overview.mdx @@ -23,4 +23,4 @@ See the [AI Actions Quick Start](/ai/ai-actions/overview#quick-start) to get sta ## Get notified -Want to be notified when AI Builder launches? [Join our Discord](https://discord.com/invite/b9UuaZRyaB) or [watch on GitHub](https://github.com/Harbour-Enterprises/SuperDoc). +Want to be notified when AI Builder launches? [Join Discord](https://discord.com/invite/b9UuaZRyaB) or [watch on GitHub](https://github.com/superdoc-dev/superdoc). diff --git a/apps/docs/api-reference/authentication.mdx b/apps/docs/api-reference/authentication.mdx index c681173231..3aaa4e88d7 100644 --- a/apps/docs/api-reference/authentication.mdx +++ b/apps/docs/api-reference/authentication.mdx @@ -11,7 +11,7 @@ Authorization: Bearer sd_sk_abc123xyz789 [Get Your Key - Takes 2 minutes](/api-reference/quickstart) -## Production Setup +## Production setup Client-side JavaScript? Stop. Keys belong in environment variables. diff --git a/apps/docs/api-reference/introduction.mdx b/apps/docs/api-reference/introduction.mdx index eecdf0c626..c91d197ee9 100644 --- a/apps/docs/api-reference/introduction.mdx +++ b/apps/docs/api-reference/introduction.mdx @@ -1,14 +1,14 @@ --- -title: Meet our API +title: Meet the API sidebarTitle: Introduction keywords: "superdoc api, docx api reference, word editor api, document editor sdk, api documentation" --- -Your documents are never persisted. Every API call is stateless—we process and forget. That's the point. +Your documents are never persisted. Every API call is stateless — process and forget. That's the point. Convert contracts to PDF. Add signatures to agreements. Merge quarterly reports. Everything preserves—tracked changes, complex tables, nested lists, headers. Real document operations via REST API. -## Why Stateless Matters +## Why stateless matters Enterprise documents contain sensitive data. NDAs, financial reports, legal contracts. SuperDoc's API processes them in memory and returns results immediately. No storage. No persistence. No risk. @@ -25,7 +25,7 @@ Bearer token in every request (except `/v1/health`): Authorization: Bearer sd_sk_abc123xyz789 ``` -## What's Working Now +## What's working now **Convert** - DOCX to PDF with perfect fidelity. That 50-page contract with tracked changes? Converts flawlessly. @@ -51,13 +51,13 @@ POST /v1/sign POST /v1/verify ``` -## What's Coming +## What's coming `/merge` - Combine documents with formatting intact.
-## Built for Real Documents +## Built for real documents -This isn't a wrapper around LibreOffice. We built custom document processing that handles: +This isn't a wrapper around LibreOffice. SuperDoc uses custom document processing that handles: - Tables spanning multiple pages - Tracked changes from multiple reviewers @@ -65,9 +65,9 @@ This isn't a wrapper around LibreOffice. We built custom document processing tha - Complex numbered lists and cross-references - Headers/footers with dynamic fields -Your Word documents work because we built for Word documents. Not markdown. Not HTML - Actual DOCX files. +Your Word documents work because SuperDoc was built for Word documents. Not markdown. Not HTML — actual DOCX files. ## Resources **[Status Page](https://status.superdoc.dev)** - Uptime and incidents -**[GitHub](https://github.com/Harbour-Enterprises/SuperDoc)** - Examples and issues +**[GitHub](https://github.com/superdoc-dev/superdoc)** - Examples and issues diff --git a/apps/docs/api-reference/quickstart.mdx b/apps/docs/api-reference/quickstart.mdx index 3b1482627a..46bd8d632d 100644 --- a/apps/docs/api-reference/quickstart.mdx +++ b/apps/docs/api-reference/quickstart.mdx @@ -17,7 +17,7 @@ Three minutes to your first response. ```bash curl "https://api.superdoc.dev/v1/auth/verify?email=you@email.com&code=123456" ``` - Save this key. We can't recover it. + Save this key. It can't be recovered. diff --git a/apps/docs/core/superdoc/configuration.mdx b/apps/docs/core/superdoc/configuration.mdx index 19831c715c..fa9bf3f0bd 100644 --- a/apps/docs/core/superdoc/configuration.mdx +++ b/apps/docs/core/superdoc/configuration.mdx @@ -5,7 +5,7 @@ keywords: "superdoc configuration, editor config options, document settings, wor Configuration is passed when creating a SuperDoc instance. Only two fields are required. -## Quick Start +## Quick start ```javascript new SuperDoc({ @@ -14,11 +14,16 @@ new SuperDoc({ }); ``` -## Core Parameters +## Core parameters - DOM selector or element where SuperDoc will mount ```javascript selector: - '#editor' // or selector: document.querySelector('.my-editor') ``` + DOM selector or element where SuperDoc will mount. + + ```javascript + selector: '#editor' + // or + selector: document.querySelector('.my-editor') + ``` @@ -63,7 +68,7 @@ new SuperDoc({ Auto-generated UUID if not provided -## User & Permissions +## User & permissions Current user information @@ -87,8 +92,9 @@ new SuperDoc({ User permission level - - `editor` - Full editing capabilities - `viewer` - Read-only access - - `suggester` - Can only suggest changes + - `editor` - Full editing capabilities + - `viewer` - Read-only access + - `suggester` - Can only suggest changes Role overrides documentMode when more restrictive @@ -96,8 +102,9 @@ new SuperDoc({ Initial document mode - - `editing` - Normal editing - `viewing` - Read-only display - `suggesting` - - Track changes enabled + - `editing` - Normal editing + - `viewing` - Read-only display + - `suggesting` - Track changes enabled @@ -143,7 +150,7 @@ new SuperDoc({ Configure optional modules -### Collaboration Module +### Collaboration module Real-time collaboration settings @@ -163,7 +170,7 @@ new SuperDoc({ -### Comments Module +### Comments module Comments system configuration @@ -183,7 +190,7 @@ new SuperDoc({ -### Toolbar Module +### Toolbar module Toolbar configuration @@ -227,11 +234,6 @@ new SuperDoc({ Built-in palette provided by default - - Enable page-based layout - Consider using `viewOptions` for more control over document layout - - Document view options for controlling layout @@ -249,17 +251,11 @@ new SuperDoc({ - **Deprecated in v1.0** - Use `viewOptions.layout` instead. - - Legacy layout mode option from v0.x. Mapped values: - - `'paginated'` → `viewOptions: { layout: 'print' }` - - `'responsive'` → `viewOptions: { layout: 'web' }` + **Removed in v1.0** — Use `viewOptions.layout` instead. `'paginated'` → `'print'`, `'responsive'` → `'web'`. - **Deprecated in v1.0** - No longer supported. Use CSS to control margins in web layout mode. - - Legacy margin configuration from v0.x. + **Removed in v1.0** — Use CSS to control margins in web layout mode. @@ -271,17 +267,12 @@ new SuperDoc({ Alternative to `modules.toolbar.selector` -## Advanced Options +## Advanced options Additional SuperDoc extensions - - Learn how to create your own extensions - [here](/extensions/creating-extensions). - - Custom image upload handler @@ -299,19 +290,20 @@ new SuperDoc({ ``` - - Telemetry configuration - - - Enable telemetry - - - License key - - - Telemetry endpoint - - + + **Deprecated since v1.8** — This option is no longer supported and will be ignored. + + + + Override document content with a JSON schema. Used to load documents from a previously exported JSON representation instead of a DOCX file. + + ```javascript + jsonOverride: { type: 'doc', content: [...] } + ``` + + + + Font family used for all SuperDoc UI elements (toolbar, comments, etc.) @@ -326,7 +318,7 @@ new SuperDoc({ Content Security Policy nonce -## Event Handlers +## Event handlers All handlers are optional functions in the configuration: @@ -340,9 +332,13 @@ All handlers are optional functions in the configuration: ``` + + Called before an editor is created + + Called when editor is created - + ```javascript onEditorCreate: ({ editor }) => { editor.focus(); @@ -360,4 +356,18 @@ All handlers are optional functions in the configuration: ``` + + Called when the comments sidebar is toggled + + + + Called when an error occurs + + ```javascript + onException: ({ error }) => { + console.error('SuperDoc error:', error); + } + ``` + + See [Events](/core/superdoc/events) for complete list. diff --git a/apps/docs/core/superdoc/events.mdx b/apps/docs/core/superdoc/events.mdx index ffea1eb48a..47ef05628b 100644 --- a/apps/docs/core/superdoc/events.mdx +++ b/apps/docs/core/superdoc/events.mdx @@ -5,74 +5,42 @@ keywords: "superdoc events, document events, editor callbacks, word editor liste SuperDoc uses an event system for lifecycle hooks and change notifications. -## Event Methods - -### Subscribe to Events - - - Event name to listen for - - - - Callback function - +## Subscribing to events ```javascript -// Regular subscription -superdoc.on('ready', handler); - -// One-time listener -superdoc.once('ready', handler); - -// Unsubscribe -superdoc.off('ready', handler); +superdoc.on('ready', handler); // Subscribe +superdoc.once('ready', handler); // One-time listener +superdoc.off('ready', handler); // Unsubscribe ``` -## Event Categories - - - - Initialization and teardown - - - Document changes - - - Multi-user events - - - Interface changes - - - -## Lifecycle Events +## Lifecycle events ### `ready` Fired when SuperDoc is fully initialized. - - SuperDoc instance - - ```javascript superdoc.on('ready', ({ superdoc }) => { - console.log('SuperDoc ready'); // Safe to use all features }); ``` +### `editorBeforeCreate` + +Fired before an editor is created. Use this to configure extensions or set up services. + +```javascript +superdoc.on('editorBeforeCreate', ({ editor }) => { + // Configure before editor mounts +}); +``` + ### `editorCreate` When an editor is created. - - Created editor instance - - ```javascript superdoc.on('editorCreate', ({ editor }) => { - console.log('Editor created'); editor.focus(); }); ``` @@ -81,29 +49,21 @@ superdoc.on('editorCreate', ({ editor }) => { When an editor is destroyed. -No parameters passed - ```javascript superdoc.on('editorDestroy', () => { - console.log('Editor destroyed'); cleanup(); }); ``` -## Content Events +## Content events ### `editor-update` When editor content changes. - - Editor with updated content - - ```javascript superdoc.on('editor-update', ({ editor }) => { - const content = editor.getJSON(); - autoSave(content); + autoSave(editor.getJSON()); }); ``` @@ -111,79 +71,44 @@ superdoc.on('editor-update', ({ editor }) => { When content processing fails. - - Error details - - - - Related editor instance - - - - Document identifier - - - - Original file - - ```javascript -superdoc.on('content-error', ({ error, editor }) => { +superdoc.on('content-error', ({ error, editor, documentId }) => { console.error('Content error:', error); - handleError(error); }); ``` ### `fonts-resolved` -When the document fonts are resolved. - - - Object with document fonts and unsupported fonts - +When document fonts are resolved. ```javascript superdoc.on('fonts-resolved', ({ documentFonts, unsupportedFonts }) => { if (unsupportedFonts.length > 0) { - console.warn('Some fonts in the document are not supported.', unsupportedFonts.join(', ')) + console.warn('Unsupported fonts:', unsupportedFonts.join(', ')); } -}) +}); ``` -## Comments Events +## Comments events ### `comments-update` When comments are modified. - - Event type: 'add', 'update', 'deleted', 'resolved' - - - - Comment data - - ```javascript superdoc.on('comments-update', ({ type, data }) => { - console.log('Comment event:', type); - refreshCommentsList(); + // type: 'add', 'update', 'deleted', 'resolved' }); ``` -## Collaboration Events +## Collaboration events ### `collaboration-ready` When collaboration is initialized. - - Editor with collaboration - - ```javascript superdoc.on('collaboration-ready', ({ editor }) => { - console.log('Collaboration active'); showOnlineUsers(); }); ``` @@ -192,14 +117,6 @@ superdoc.on('collaboration-ready', ({ editor }) => { When user presence changes. - - Awareness context - - - - User states map - - ```javascript superdoc.on('awareness-update', ({ context, states }) => { const users = Array.from(states.values()); @@ -211,14 +128,6 @@ superdoc.on('awareness-update', ({ context, states }) => { When document lock state changes. - - Lock state - - - - User who locked the document - - ```javascript superdoc.on('locked', ({ isLocked, lockedBy }) => { if (isLocked) { @@ -227,102 +136,53 @@ superdoc.on('locked', ({ isLocked, lockedBy }) => { }); ``` -## Configuration-Based Events +## UI events - -Events can also be configured during initialization - +### `sidebar-toggle` -```javascript -new SuperDoc({ - selector: '#editor', - document: 'document.docx', - - // Event handlers in config - onReady: ({ superdoc }) => { - console.log('Ready from config'); - }, - - onEditorUpdate: ({ editor }) => { - autoSave(editor.getJSON()); - }, - - onFontsResolved: ({ documentFonts, unsupportedFonts }) => { - console.log(`Found ${documentFonts.length} in the document`) - } -}); -``` - -## Common Patterns - -### Auto-save with Debouncing +When the comments sidebar is toggled. ```javascript -import { debounce } from 'lodash'; - -const save = debounce(async (content) => { - await api.saveDocument(content); -}, 1000); - -superdoc.on('editor-update', ({ editor }) => { - save(editor.getJSON()); +superdoc.on('sidebar-toggle', (isOpened) => { + adjustLayout(isOpened); }); ``` -### Track Multiple Editors +## Error events -```javascript -const editors = new Map(); +### `exception` -superdoc.on('editorCreate', ({ editor }) => { - const id = editor.options.documentId; - editors.set(id, editor); -}); +When an error occurs during document processing or runtime. -superdoc.on('editorDestroy', () => { - editors.clear(); +```javascript +superdoc.on('exception', ({ error, document, editor }) => { + console.error('SuperDoc error:', error); }); ``` -### Clean Up Pattern +## Configuration-based events -```javascript -const handlers = { - ready: () => console.log('Ready'), - update: () => console.log('Updated') -}; - -// Subscribe -Object.entries(handlers).forEach(([event, handler]) => { - superdoc.on(event, handler); -}); +Events can also be set during initialization: -// Later: Unsubscribe all -Object.entries(handlers).forEach(([event, handler]) => { - superdoc.off(event, handler); +```javascript +new SuperDoc({ + selector: '#editor', + document: 'document.docx', + onReady: ({ superdoc }) => { }, + onEditorBeforeCreate: ({ editor }) => { }, + onEditorCreate: ({ editor }) => { }, + onEditorUpdate: ({ editor }) => { }, + onFontsResolved: ({ documentFonts, unsupportedFonts }) => { }, + onSidebarToggle: (isOpened) => { }, + onException: ({ error }) => { }, }); ``` -## Event Order - - -Understanding event order helps with initialization: - -1. `editorBeforeCreate` - Setup phase -2. `editorCreate` - Editor ready -3. `ready` - All editors ready -4. `collaboration-ready` - If enabled -5. Runtime events -6. `editorDestroy` - Cleanup - - -## Performance Tips - - -**Best practices:** -- Use `once()` for one-time setup -- Debounce expensive handlers -- Clean up with `off()` when done -- Avoid heavy work in `awareness-update` -- Batch updates in `editor-update` - \ No newline at end of file +## Event order + +1. `editorBeforeCreate` — Before editor mounts +2. `editorCreate` — Editor ready +3. `ready` — All editors ready +4. `collaboration-ready` — If collaboration enabled +5. Runtime events (`editor-update`, `comments-update`, `sidebar-toggle`, etc.) +6. `editorDestroy` — Cleanup diff --git a/apps/docs/core/superdoc/methods.mdx b/apps/docs/core/superdoc/methods.mdx index 7bd266ccaf..a1ffe8a3a6 100644 --- a/apps/docs/core/superdoc/methods.mdx +++ b/apps/docs/core/superdoc/methods.mdx @@ -5,7 +5,7 @@ keywords: "superdoc methods, document api methods, editor functions, word docume Methods are functions you call on the SuperDoc instance to perform actions. -## Document Operations +## Document operations ### `export` @@ -13,7 +13,7 @@ Export the document with various options. Export configuration - + Export formats @@ -61,7 +61,7 @@ Get HTML content of all editors. HTML options - + Preserve nested list structure @@ -75,7 +75,7 @@ Get HTML content of all editors. const htmlArray = superdoc.getHTML(); ``` -## Mode Control +## Mode control ### `setDocumentMode` @@ -83,7 +83,7 @@ Change the document mode. New document mode - + - `'viewing'` - Read-only - `'suggesting'` - Track changes @@ -123,7 +123,50 @@ Enable/disable high contrast mode. superdoc.setHighContrastMode(true); ``` -## UI Methods +## UI methods + +### `setActiveEditor` + +Set which editor is currently active. Useful when working with multiple documents. + + + Editor instance to set as active + + +```javascript +superdoc.setActiveEditor(editor); +``` + +### `setDisableContextMenu` + +Toggle the custom context menu at runtime. + + + Whether to disable the context menu + + +```javascript +superdoc.setDisableContextMenu(true); +``` + +### `setTrackedChangesPreferences` + +Override how tracked changes are rendered in the layout engine. + + + + + Rendering mode: `'review'`, `'original'`, `'final'`, or `'off'` + + + Whether tracked change metadata is included + + + + +```javascript +superdoc.setTrackedChangesPreferences({ mode: 'final' }); +``` ### `toggleRuler` @@ -133,13 +176,11 @@ Toggle ruler visibility. superdoc.toggleRuler(); ``` -### `togglePagination` + -Toggle pagination mode. +**Removed in v1.0** — Pagination is now handled by the layout engine. Use `viewOptions.layout` in [configuration](/core/superdoc/configuration) instead. -```javascript -superdoc.togglePagination(); -``` + ### `focus` @@ -149,7 +190,7 @@ Focus the active editor or first available. superdoc.focus(); ``` -## Search Methods +## Search methods ### `search` @@ -178,7 +219,7 @@ Navigate to a search result. superdoc.goToSearchResult(results[0]); ``` -## Comments Methods +## Comments methods ### `addCommentsList` @@ -200,7 +241,7 @@ Remove the comments list. superdoc.removeCommentsList(); ``` -## User Management +## User management ### `addSharedUser` @@ -208,7 +249,7 @@ Add a user to the shared users list. User to add - + Display name @@ -238,7 +279,7 @@ Remove a user from shared users. superdoc.removeSharedUser('jane@example.com'); ``` -## Lifecycle Methods +## Lifecycle ### `destroy` @@ -250,20 +291,12 @@ Completely destroy the SuperDoc instance. superdoc.destroy(); ``` -## Event Methods +## Event methods ### `on` Subscribe to an event. - - Event name - - - - Event handler - - ```javascript superdoc.on('ready', ({ superdoc }) => { console.log('SuperDoc ready'); @@ -274,14 +307,6 @@ superdoc.on('ready', ({ superdoc }) => { Subscribe to an event once. - - Event name - - - - Event handler - - ```javascript superdoc.once('ready', () => { // Only called once @@ -292,43 +317,74 @@ superdoc.once('ready', () => { Unsubscribe from an event. - - Event name - - - - Handler to remove - - ```javascript superdoc.off('ready', handler); ``` -## Method Patterns +## Schema introspection + +### `getSchemaIntrospection` -### Async Operations +Returns a JSON schema summary with all nodes, marks, and their attributes. Useful for AI agents that need schema context. ```javascript -async function exportDocument() { - try { - const blob = await superdoc.export({ - isFinalDoc: true - }); - saveToFile(blob); - } catch (error) { - console.error('Export failed:', error); - } -} +import { getSchemaIntrospection } from 'superdoc'; + +const schema = await getSchemaIntrospection({ mode: 'docx' }); +// Returns: { version, nodes: [...], marks: [...] } ``` -### Waiting for Ready + + + + Existing Editor instance to introspect. If provided, uses this instead of creating a temporary editor. + + + Custom extensions to use when building the schema. + + + Editor mode: `'docx'`, `'html'`, or `'text'` + + + + +## TypeScript types + +SuperDoc exports TypeScript interfaces for all node and mark types: + +```typescript +import type { NodeName, NodeAttrs, ParagraphAttrs } from 'superdoc/types'; + +// NodeName shows all 39 node types in autocomplete +type Test = NodeAttrs<'paragraph'>; // Resolves to ParagraphAttrs +``` -Some methods require SuperDoc to be ready +Available types: `NodeName`, `NodeAttrs`, `MarkName`, `MarkAttrs`, and specific interfaces like `ParagraphAttrs`, `TableAttrs`, `ImageAttrs`, etc. + +## Properties + +### `activeEditor` + +Currently active editor instance. Returns `null` before the `ready` event. ```javascript -superdoc.once('ready', () => { - // Now safe to use all methods - superdoc.search('term'); - superdoc.setDocumentMode('suggesting'); -}); -``` \ No newline at end of file +if (superdoc.activeEditor) { + superdoc.activeEditor.commands.toggleBold(); +} +``` + +Always check for `null` before accessing. + +| Property | Type | Description | +|---|---|---| +| `superdocId` | `string` | Unique identifier for this instance | +| `version` | `string` | SuperDoc version number | +| `activeEditor` | `Editor \| null` | Currently active editor | +| `element` | `HTMLElement \| null` | Container DOM element | +| `state` | `{ documents, users }` | Current state snapshot | +| `isLocked` | `boolean` | Whether the document is locked | +| `lockedBy` | `User \| null` | User who locked the document | +| `isCollaborative` | `boolean` | Whether collaboration is enabled | +| `user` | `User` | Current user information | +| `users` | `User[]` | All users with document access | +| `toolbar` | `Toolbar \| null` | Toolbar instance if configured | diff --git a/apps/docs/core/superdoc/overview.mdx b/apps/docs/core/superdoc/overview.mdx index fc9a1232ff..f18f2854c8 100644 --- a/apps/docs/core/superdoc/overview.mdx +++ b/apps/docs/core/superdoc/overview.mdx @@ -9,7 +9,7 @@ The SuperDoc instance is your main interface for controlling the DOCX editor. It ## Creating an instance ```javascript -import { SuperDoc } from '@harbour-enterprises/superdoc'; +import { SuperDoc } from 'superdoc'; const superdoc = new SuperDoc({ selector: '#editor', @@ -39,7 +39,5 @@ superdoc.destroy(); ## API structure - **[Configuration](/core/superdoc/configuration)** - Settings passed at creation -- **[Methods](/core/superdoc/methods)** - Functions to control the editor -- **[Properties](/core/superdoc/properties)** - Access to state and sub-systems +- **[Methods](/core/superdoc/methods)** - Control the editor, access properties and types - **[Events](/core/superdoc/events)** - Lifecycle and change notifications -``` diff --git a/apps/docs/core/superdoc/properties.mdx b/apps/docs/core/superdoc/properties.mdx deleted file mode 100644 index 914412e38e..0000000000 --- a/apps/docs/core/superdoc/properties.mdx +++ /dev/null @@ -1,273 +0,0 @@ ---- -title: Properties -keywords: "superdoc properties, editor state, document properties, word editor attributes, api properties" ---- - -Properties provide read-only access to SuperDoc's internal state and subsystems. - -## Core Properties - -### `superdocId` - - - Unique identifier for this SuperDoc instance - - ```javascript - console.log(superdoc.superdocId); - // "550e8400-e29b-41d4-a716-446655440000" - ``` - - -### `version` - - - SuperDoc version number - - ```javascript - console.log(superdoc.version); - // "2.1.0" - ``` - - -## Editor Access - -### `activeEditor` - - - Currently active editor instance - - Always check for null before accessing - - ```javascript - if (superdoc.activeEditor) { - // Direct ProseMirror access - superdoc.activeEditor.commands.toggleBold(); - - // Access state - const { doc, selection } = superdoc.activeEditor.state; - - // Access view - superdoc.activeEditor.view.focus(); - } - ``` - - -## State Properties - -### Document State - - - Whether the document is locked - - - - User who locked the document - - - - Whether collaboration is enabled - - - - Whether in development mode - - -```javascript -if (superdoc.isLocked) { - console.log(`Locked by ${superdoc.lockedBy.name}`); -} - -if (superdoc.isCollaborative) { - showCollaboratorsList(); -} -``` - -## User Properties - -### Current User - - - Current user information - - - - Display name - - - Email address - - - Avatar URL - - - - -### All Users - - - All users with document access - - - - Available colors for awareness - - -```javascript -superdoc.users.forEach(user => { - console.log(`${user.name} (${user.email})`); -}); -``` - -## Subsystem Access - -### Toolbar - - - Toolbar instance if configured - - ```javascript - if (superdoc.toolbar) { - superdoc.toolbar.updateToolbarState(); - } - ``` - - -### Collaboration - - - Collaboration provider for the SuperDoc level - - - - Yjs document for collaboration - - - - WebSocket connection - - -```javascript -if (superdoc.provider) { - superdoc.provider.on('synced', () => { - console.log('Synced with server'); - }); -} -``` - -## Store Access - -### Document Store - - - Pinia store for document management - - ```javascript - const documents = superdoc.superdocStore.documents; - documents.forEach(doc => { - console.log(doc.id, doc.type); - }); - ``` - - -### Comments Store - - - Pinia store for comments - - ```javascript - const comments = superdoc.commentsStore.comments; - console.log(`${comments.length} comments`); - ``` - - -### High Contrast Store - - - Store for high contrast mode state - - ```javascript - const isHighContrast = superdoc.highContrastModeStore.isEnabled; - ``` - - -## Internal Properties - - -These properties are for advanced use cases - - - - Full configuration object - - - - Vue application instance - - - - Pinia store instance - - - - Comments list component - - -## Property Usage - - -Properties are read-only. Use methods to modify state: - -```javascript -// ❌ Don't modify directly -superdoc.isLocked = true; -superdoc.activeEditor = newEditor; - -// ✅ Use methods -superdoc.lockSuperdoc(true); -superdoc.setActiveEditor(newEditor); -``` - - -## Common Patterns - -### Check Before Access - -```javascript -// Always check nullable properties -if (superdoc.activeEditor) { - superdoc.activeEditor.focus(); -} - -if (superdoc.toolbar) { - superdoc.toolbar.updateState(); -} -``` - -### Wait for Ready - -Some properties only available after ready event - -```javascript -superdoc.once('ready', () => { - // Now safe to access - console.log(superdoc.activeEditor); - console.log(superdoc.toolbar); -}); -``` - -### Direct Editor Access - -```javascript -// Get ProseMirror state -const getSelection = () => { - if (!superdoc.activeEditor) return null; - - const { from, to } = superdoc.activeEditor.state.selection; - return { from, to }; -}; - -// Execute commands -const makeBold = () => { - superdoc.activeEditor?.commands.toggleBold(); -}; -``` \ No newline at end of file diff --git a/apps/docs/core/superdoc/types.mdx b/apps/docs/core/superdoc/types.mdx deleted file mode 100644 index f512ca6d3d..0000000000 --- a/apps/docs/core/superdoc/types.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: TypeScript Types -sidebarTitle: Types -keywords: "superdoc typescript, document types, node types, mark types, type safety, schema introspection" ---- - -This is useful for building AI drafting agents and ensuring type-safe document manipulation. - -## TypeScript Types Export - -Exports TypeScript interfaces for all node and mark types: - -- `NodeName` - union of all valid node names (expands in IDE hover tooltips) -- `NodeAttrs` - get attribute type for a specific node -- `MarkName`, `MarkAttrs` - same for marks -- Includes all specific attribute interfaces (`ParagraphAttrs`, `TableAttrs`, `ImageAttrs`, etc.) - -```typescript -import type { NodeName, NodeAttrs, ParagraphAttrs } from 'superdoc/types'; - -// NodeName shows all 39 node types in autocomplete -type Test = NodeAttrs<'paragraph'>; // Resolves to ParagraphAttrs -``` - -## Schema Introspection - -Returns JSON schema summary with all nodes, marks, and their attributes. Useful for AI agents that need schema context for prompt engineering. - -Supports different modes: `docx`, `html`, `text` - -```javascript -import { getSchemaIntrospection } from '@harbour-enterprises/superdoc'; - -const schema = await getSchemaIntrospection({ mode: 'docx' }); -// Returns: { version, nodes: [...], marks: [...] } -``` - -### Options - - - Configuration options - - - - Existing Editor instance to introspect. If provided, uses this instead of creating a temporary editor. - - - Custom extensions to use when building the schema. - - - Editor mode: `'docx'`, `'html'`, or `'text'` - - - - -### Response - -```json -{ - "version": "1.8.2", - "schemaVersion": "current", - "topNode": "doc", - "nodes": [ - { - "name": "paragraph", - "attrs": { - "paragraphProperties": { "default": null, "required": false } - }, - "group": "block", - "content": "inline*" - } - ], - "marks": [ - { - "name": "bold", - "attrs": {}, - "group": "formatting" - } - ] -} -``` diff --git a/apps/docs/core/supereditor/configuration.mdx b/apps/docs/core/supereditor/configuration.mdx index 874ae10e2b..5776292c85 100644 --- a/apps/docs/core/supereditor/configuration.mdx +++ b/apps/docs/core/supereditor/configuration.mdx @@ -5,80 +5,67 @@ keywords: "supereditor config, editor configuration, prosemirror setup, document SuperEditor configuration gives you low-level control over the DOCX engine. -## Quick Start +## Quick start ```javascript import "superdoc/style.css"; -import { Editor, getStarterExtensions } from "superdoc/super-editor"; - -// Parse DOCX file first -const [content, media, mediaFiles, fonts] = await Editor.loadXmlData(docxFile); +import { Editor } from "superdoc/super-editor"; -// Create editor -const editor = new Editor({ - mode: "docx", - documentMode: "editing", +const editor = await Editor.open(docxFile, { element: document.getElementById("editor"), - documentId: "doc-123", - extensions: getStarterExtensions(), - fileSource: docxFile, - content, - media, - mediaFiles, - fonts, + documentMode: "editing", }); ``` -## Required Parameters +`Editor.open()` is the recommended way to create an editor. It handles DOCX parsing, extension setup, and mounting automatically. + +## Required parameters - - DOM element where the editor will mount + + The document source. Can be a file path (Node.js), File/Blob (browser), or Buffer. ```javascript -element: document.getElementById("editor"); -``` +// Browser +const editor = await Editor.open(file, { element: el }); - +// Node.js +const editor = await Editor.open('/path/to/doc.docx'); + +// Blank document +const editor = await Editor.open(); +``` - - Unique identifier for this document instance. Used for collaboration and - storage. - - Extensions that define the editor schema and functionality. + + DOM element where the editor will mount. If omitted, the editor runs in headless mode. ```javascript -import { getStarterExtensions } from "superdoc/super-editor"; - -extensions: getStarterExtensions(); +element: document.getElementById("editor"); ``` -## DOCX Mode Parameters - - - The DOCX file to load + + Unique identifier for this document instance. Used for collaboration and + storage. Auto-generated if not provided. - - Parsed XML content from `Editor.loadXmlData()` - + + Extensions that define the editor schema and functionality. If omitted, `Editor.open()` uses sensible defaults (`getStarterExtensions()` for DOCX, `getRichTextExtensions()` for text/HTML). - - Media file mappings from `Editor.loadXmlData()` - +```javascript +import { getStarterExtensions } from "superdoc/super-editor"; - - Media blob data from `Editor.loadXmlData()` - +const editor = await Editor.open(file, { + element: el, + extensions: getStarterExtensions(), // explicit, but also the default for DOCX +}); +``` - - Font configuration from `Editor.loadXmlData()` -## Modes & Permissions +## Modes & permissions Editor rendering mode @@ -110,7 +97,7 @@ extensions: getStarterExtensions(); Whether the editor accepts input -## User & Collaboration +## User & collaboration Current user information @@ -140,7 +127,7 @@ extensions: getStarterExtensions(); Provider instance for collaboration sync -## Content Initialization +## Content initialization Initialize with HTML content (for `mode: 'html'`) @@ -150,7 +137,7 @@ extensions: getStarterExtensions(); Initialize with Markdown (converts to document) - + Use ProseMirror JSON content instead of DOCX parsing @@ -168,11 +155,11 @@ extensions: getStarterExtensions(); Enable page-based layout -## Advanced Options +## Advanced options Run without mounting an editor view (Node.js/server-side processing). - You must provide `document` from JSDOM for serialization methods like `getHTML()`. + Automatically set to `true` when no `element` is provided to `Editor.open()`. @@ -183,14 +170,6 @@ extensions: getStarterExtensions(); Y.Doc XML fragment for collaborative document content. Use with headless mode to read Y.Doc content. - - **Deprecated.** Use `document` instead. - - - - **Deprecated.** No longer required — just pass `document`. - - Custom image upload handler @@ -203,36 +182,22 @@ handleImageUpload: async (file) => { -## Configuration Patterns +## Configuration patterns -### Full DOCX Editor +### Full DOCX editor ```javascript import "superdoc/style.css"; -import { Editor, getStarterExtensions } from "superdoc/super-editor"; +import { Editor } from "superdoc/super-editor"; -async function createDocxEditor(docxFile) { - const [content, media, mediaFiles, fonts] = await Editor.loadXmlData( - docxFile - ); - - return new Editor({ - mode: "docx", - documentMode: "editing", - element: document.getElementById("editor"), - documentId: "doc-123", - extensions: getStarterExtensions(), - fileSource: docxFile, - content, - media, - mediaFiles, - fonts, - user: { name: "John", email: "john@example.com" }, - }); -} +const editor = await Editor.open(docxFile, { + element: document.getElementById("editor"), + documentMode: "editing", + user: { name: "John", email: "john@example.com" }, +}); ``` -### Headless Converter (Node.js) +### Headless converter (Node.js) Convert DOCX files server-side without a browser using JSDOM. @@ -244,33 +209,10 @@ Convert DOCX files server-side without a browser using JSDOM. ```javascript import { readFile } from "fs/promises"; -import { JSDOM } from "jsdom"; -import { Editor, getStarterExtensions } from "superdoc/super-editor"; +import { Editor } from "superdoc/super-editor"; -const { window } = new JSDOM(""); -const { document } = window; - -// Pass `true` as second arg for Node.js const buffer = await readFile("document.docx"); -const [content, media, mediaFiles, fonts] = await Editor.loadXmlData( - buffer, - true -); - -const editor = new Editor({ - mode: "docx", - documentId: "headless", - element: document.createElement("div"), - extensions: getStarterExtensions(), - fileSource: buffer, - content, - media, - mediaFiles, - fonts, - isHeadless: true, - mockDocument: document, - mockWindow: window, -}); +const editor = await Editor.open(buffer); // Output formats const html = editor.getHTML(); @@ -281,60 +223,41 @@ const markdown = await editor.getMarkdown(); editor.destroy(); ``` -### Headless Y.Doc to HTML (Collaboration) +### Headless Y.Doc to HTML (collaboration) Read content from a collaborative Y.Doc in your backend — useful for AI agents or APIs that need to access document content without a browser. - Even with `isHeadless: true`, methods like `getHTML()` need a DOM for serialization. Always set up JSDOM first. + Even with headless mode, methods like `getHTML()` need a DOM for serialization. JSDOM is set up automatically in Node.js when using `Editor.open()`. ```javascript -import { JSDOM } from "jsdom"; import { Editor, getStarterExtensions } from "superdoc/super-editor"; -// Set up JSDOM -const { window } = new JSDOM(""); - // Get the YXmlFragment from your Y.Doc const fragment = ydoc.getXmlFragment("prosemirror"); const editor = new Editor({ mode: "docx", isHeadless: true, - document: window.document, extensions: getStarterExtensions(), - fragment, // YXmlFragment from Y.Doc + fragment, }); const html = editor.getHTML(); editor.destroy(); ``` - - The `document` option replaces the deprecated `mockDocument` and `mockWindow` options. - - -### Custom Collaboration +### Custom collaboration ```javascript -import { Editor, getStarterExtensions } from "superdoc/super-editor"; +import { Editor } from "superdoc/super-editor"; import * as Y from "yjs"; import { HocuspocusProvider } from "@hocuspocus/provider"; -const [content, media, mediaFiles, fonts] = await Editor.loadXmlData(docxFile); - -const editor = new Editor({ - mode: "docx", - documentMode: "editing", +const editor = await Editor.open(docxFile, { element: document.getElementById("editor"), - documentId: roomId, - extensions: getStarterExtensions(), - fileSource: docxFile, - content, - media, - mediaFiles, - fonts, + documentMode: "editing", ydoc: new Y.Doc(), collaborationProvider: new HocuspocusProvider({ url: "wss://collab.example.com", @@ -345,22 +268,14 @@ const editor = new Editor({ }); ``` -### Track Changes Mode +### Track changes mode ```javascript -const [content, media, mediaFiles, fonts] = await Editor.loadXmlData(docxFile); +import { Editor } from "superdoc/super-editor"; -const editor = new Editor({ - mode: "docx", - documentMode: "suggesting", +const editor = await Editor.open(docxFile, { element: document.getElementById("editor"), - documentId: "review-doc", - extensions: getStarterExtensions(), - fileSource: docxFile, - content, - media, - mediaFiles, - fonts, + documentMode: "suggesting", user: reviewer, }); ``` diff --git a/apps/docs/core/supereditor/events.mdx b/apps/docs/core/supereditor/events.mdx new file mode 100644 index 0000000000..18e2615f21 --- /dev/null +++ b/apps/docs/core/supereditor/events.mdx @@ -0,0 +1,138 @@ +--- +title: Events +keywords: "supereditor events, editor lifecycle, document events, editor callbacks, editor hooks" +--- + +Events let you respond to editor lifecycle and content changes. + +## Lifecycle + +### `onBeforeCreate` + +Called before the editor view is created. + +```javascript +onBeforeCreate: ({ editor }) => { + // Set up external services +} +``` + +### `onCreate` + +Called when editor is fully initialized and ready. + +```javascript +onCreate: ({ editor }) => { + editor.focus(); +} +``` + +### `onDestroy` + +Called when editor is being destroyed. Clean up resources here. + +```javascript +onDestroy: () => { + clearInterval(autoSaveTimer); +} +``` + +### `onFirstRender` + +Called after the first render completes. + +```javascript +onFirstRender: () => { + hideLoadingSpinner(); +} +``` + +## Content + +### `onUpdate` + +Called when document content changes. + +```javascript +onUpdate: ({ editor, transaction }) => { + if (transaction.docChanged) { + saveToBackend(editor.getJSON()); + } +} +``` + +### `onContentError` + +Called when content processing fails. + +```javascript +onContentError: ({ error, editor, documentId }) => { + console.error('Document error:', error); +} +``` + +## Selection + +### `onSelectionUpdate` + +Called when selection changes (cursor movement). + +```javascript +onSelectionUpdate: ({ editor }) => { + toolbar.bold = editor.isActive('bold'); +} +``` + +### `onFocus` + +Called when editor gains focus. + +```javascript +onFocus: ({ editor, event }) => { + showFormattingToolbar(); +} +``` + +### `onBlur` + +Called when editor loses focus. + +```javascript +onBlur: ({ editor, event }) => { + saveCurrentState(); +} +``` + +## Features + +### `onCommentsUpdate` + +```javascript +onCommentsUpdate: ({ editor }) => { + updateCommentsSidebar(); +} +``` + +### `onCommentsLoaded` + +```javascript +onCommentsLoaded: ({ editor, comments }) => { + console.log(`Loaded ${comments.length} comments`); +} +``` + +### `onTrackedChangesUpdate` + +```javascript +onTrackedChangesUpdate: ({ editor }) => { + updateReviewPanel(); +} +``` + +### `onCollaborationReady` + +```javascript +onCollaborationReady: ({ editor, ydoc }) => { + showCollaboratorsCursors(); +} +``` diff --git a/apps/docs/core/supereditor/hooks.mdx b/apps/docs/core/supereditor/hooks.mdx deleted file mode 100644 index 23d064f23c..0000000000 --- a/apps/docs/core/supereditor/hooks.mdx +++ /dev/null @@ -1,341 +0,0 @@ ---- -title: Hooks -keywords: "supereditor hooks, editor lifecycle, prosemirror hooks, document events, editor callbacks" ---- - -Hooks let you respond to editor lifecycle and changes with fine-grained control. - -## Hook Categories - - - - Initialization and teardown - - - Document changes - - - Cursor and selection - - - Comments, track changes, etc. - - - -## Lifecycle Hooks - -### `onBeforeCreate` - -Called before the editor view is created. - - - Editor instance (partially initialized) - - -```javascript -onBeforeCreate: ({ editor }) => { - console.log('Preparing editor...'); - // Set up external services -} -``` - -### `onCreate` - -Called when editor is fully initialized and ready. - - - Fully initialized editor instance - - -```javascript -onCreate: ({ editor }) => { - console.log('Editor ready'); - editor.focus(); -} -``` - -### `onDestroy` - -Called when editor is being destroyed. - -No parameters passed. Clean up resources here. - -```javascript -onDestroy: () => { - console.log('Cleaning up...'); - clearInterval(autoSaveTimer); -} -``` - -### `onFirstRender` - -Called after the first render completes. - -```javascript -onFirstRender: () => { - measurePerformance(); - hideLoadingSpinner(); -} -``` - -## Content Hooks - -### `onUpdate` - -Called when document content changes. - - - Editor instance - - - - ProseMirror transaction - - -```javascript -onUpdate: ({ editor, transaction }) => { - if (transaction.docChanged) { - const content = editor.getJSON(); - saveToBackend(content); - } -} -``` - -### `onTransaction` - -Fires for every transaction including selection changes. Use sparingly. - - - Editor instance - - - - ProseMirror transaction - - - - Transaction processing time in milliseconds - - -```javascript -onTransaction: ({ editor, transaction, duration }) => { - if (duration > 50) { - console.warn(`Slow transaction: ${duration}ms`); - } -} -``` - -### `onContentError` - -Called when content processing fails. - - - Error object with details - - - - Error type (e.g., 'INVALID_NODE', 'CORRUPT_STATE') - - - Whether error can be recovered - - - Error description - - - - - - Editor instance - - - - Document identifier - - - - Original file that failed - - -```javascript -onContentError: ({ error, editor }) => { - if (error.recoverable) { - editor.commands.clearInvalidNodes(); - } else { - showErrorDialog(error); - } -} -``` - -## Selection Hooks - -### `onSelectionUpdate` - -Called when selection changes (cursor movement). - - - Editor instance - - - - ProseMirror transaction - - -```javascript -onSelectionUpdate: ({ editor }) => { - const { from, to } = editor.state.selection; - updateSelectionUI(from, to); - - // Update formatting buttons - toolbar.bold = editor.isActive('bold'); -} -``` - -### `onFocus` - -Called when editor gains focus. - - - Editor instance - - - - Browser focus event - - -```javascript -onFocus: ({ editor, event }) => { - showFormattingToolbar(); - trackEngagement('editor_focused'); -} -``` - -### `onBlur` - -Called when editor loses focus. - - - Editor instance - - - - Browser blur event - - -```javascript -onBlur: ({ editor, event }) => { - hideInlineMenus(); - saveCurrentState(); -} -``` - -## Feature Hooks - -### Comments Hooks - -#### `onCommentsUpdate` - - - Editor instance with updated comments - - -```javascript -onCommentsUpdate: ({ editor }) => { - const comments = editor.storage.comments.all(); - updateCommentsSidebar(comments); -} -``` - -#### `onCommentsLoaded` - - - Editor instance - - - - Loaded comments array - - - - Whether file was replaced - - -```javascript -onCommentsLoaded: ({ editor, comments }) => { - console.log(`Loaded ${comments.length} comments`); - renderCommentsList(comments); -} -``` - -### Track Changes Hooks - -#### `onTrackedChangesUpdate` - - - Editor instance with track changes - - -```javascript -onTrackedChangesUpdate: ({ editor }) => { - const changes = editor.storage.trackChanges.all(); - updateReviewPanel(changes); -} -``` - -### Collaboration Hooks - -#### `onCollaborationReady` - - - Editor instance - - - - Yjs document instance - - -```javascript -onCollaborationReady: ({ editor, ydoc }) => { - console.log('Collaboration active'); - showCollaboratorsCursors(); -} -``` - -## Common Patterns - -### Auto-save with Debouncing - -```javascript -import { debounce } from 'lodash'; - -const autoSave = debounce(async (content) => { - await api.saveDocument(content); -}, 1000); - -options: { - onUpdate: ({ editor }) => { - autoSave(editor.getJSON()); - } -} -``` - -### Error Recovery - -```javascript -options: { - onContentError: ({ error, editor }) => { - console.error('Document error:', error); - } -} -``` - -## Performance Tips - - -**Best practices for hooks:** -- Debounce expensive operations -- Use `onTransaction` sparingly -- Check `transaction.docChanged` before processing -- Clean up resources in `onDestroy` -- Batch initialization in `onCreate` - \ No newline at end of file diff --git a/apps/docs/core/supereditor/methods.mdx b/apps/docs/core/supereditor/methods.mdx index 6835e52719..e897045315 100644 --- a/apps/docs/core/supereditor/methods.mdx +++ b/apps/docs/core/supereditor/methods.mdx @@ -1,79 +1,116 @@ --- title: Methods -keywords: "supereditor methods, editor commands, prosemirror commands, document manipulation, editor api" +keywords: "supereditor methods, editor commands, document manipulation, editor api" --- - -**Looking for programmatic document access?** The [Document API](/document-api/overview) is coming soon with a stable, engine-agnostic interface for querying and manipulating documents. - +## Document lifecycle -SuperEditor exposes both high-level methods and direct ProseMirror access. +### `open` -## Content Methods +Open a document from a file, URL, or buffer. -### `getHTML` - -Get document as HTML string. + + Document source. Omit for a blank document. + - - Configuration options - + - - Preserve nested list structure + + `'docx'`, `'text'`, or `'html'` + + + HTML content (for text/html mode) + + + Markdown content + + + ProseMirror JSON to use instead of DOCX parsing -**Returns:** `string` - HTML representation +```javascript +await editor.open(docxFile); +await editor.open(null, { mode: 'html', html: '

Hello

' }); +``` + + +This is the instance method. For one-liner creation, use the static `Editor.open()` factory — see [Configuration](/core/supereditor/configuration). + + +### `close` + +Close the current document. The editor instance stays alive for reuse. ```javascript -const html = editor.getHTML(); -// With nested lists preserved -const html = editor.getHTML({ unflattenLists: true }); +editor.close(); +await editor.open(anotherFile); ``` -### `getJSON` +### `save` -Get document as ProseMirror JSON. +Save back to the original source path (Node.js only). -**Returns:** `Object` - ProseMirror document JSON + + + + Replace fields with values + + + Comment handling + + + Comments to include + + + Field highlight color + + + ```javascript -const json = editor.getJSON(); +await editor.save(); +await editor.save({ isFinalDoc: true }); ``` -### `getUpdatedJson` +Throws if the editor was opened from a Blob/Buffer instead of a file path. Use `saveTo()` or `exportDocument()` instead. + +### `saveTo` -Get JSON prepared for export with comment processing. +Save to a specific path (Node.js only). -**Returns:** `Object` - Export-ready JSON + + File path + ```javascript -const json = editor.getUpdatedJson(); +await editor.saveTo('/path/to/output.docx'); ``` -## Export Methods +### `exportDocument` + +Export as a Blob (browser) or Buffer (Node.js). + +```javascript +const blob = await editor.exportDocument(); +const blob = await editor.exportDocument({ isFinalDoc: true }); +``` ### `exportDocx` -Export document as DOCX file. +Lower-level export with additional control. - Export configuration - Replace fields with values - Comment handling: 'external', 'clean', or custom + `'external'`, `'clean'`, or custom - - Comments to include - - [Data structure](/modules/comments#comment-data-structure) + Comments to include — [data structure](/modules/comments#comment-data-structure) Field highlight color @@ -81,8 +118,6 @@ Export document as DOCX file. -**Returns:** `Promise` - DOCX file blob - ```javascript const blob = await editor.exportDocx({ isFinalDoc: true, @@ -90,479 +125,245 @@ const blob = await editor.exportDocx({ }); ``` -### `loadXmlData` - -Load and parse DOCX file data. - - - DOCX file source - - - - Whether running in Node.js - +### `replaceFile` -**Returns:** `Promise<[xmlFiles, mediaUrls, mediaBase64, fonts]>` +Replace the current DOCX with a new file. ```javascript -const [xmlFiles, mediaUrls, mediaBase64, fonts] = - await Editor.loadXmlData(docxFile); +await editor.replaceFile(newDocxFile); ``` -## Editor Control +## Content -### `mount` +### `getHTML` -Mount editor to DOM element. +```javascript +const html = editor.getHTML(); +const html = editor.getHTML({ unflattenLists: true }); +``` - - Target DOM element - +### `getJSON` ```javascript -editor.mount(document.querySelector('#new-container')); +const json = editor.getJSON(); ``` -### `unmount` - -Unmount editor from DOM (keeps instance alive). +### `getMarkdown` ```javascript -editor.unmount(); +const md = await editor.getMarkdown(); ``` -### `destroy` - -Completely destroy editor and clean up. +### `replaceContent` -This is irreversible. The editor instance cannot be used after calling destroy. +Replace the entire document content. ```javascript -editor.destroy(); +editor.replaceContent(proseMirrorJson); ``` -### `focus` +### `replaceNodeWithHTML` -Focus the editor. +Replace a specific node with HTML. ```javascript -editor.focus(); +const table = editor.getNodesOfType('table')[0]; +editor.replaceNodeWithHTML(table, '...
'); ``` -### `setEditable` - -Set editor editability. - - - Whether editor should be editable - +## Editor control - - Whether to emit update event - +### `mount` / `unmount` ```javascript -editor.setEditable(false); // Read-only -editor.setEditable(true, false); // Editable without event +editor.mount(document.querySelector('#editor')); +editor.unmount(); // Keeps instance alive ``` -## Mode Control +### `destroy` -### `setDocumentMode` +Permanently destroy the editor. -Change document editing mode. - - - Document mode - - - - `'viewing'` - Read-only - - `'suggesting'` - Track changes - - `'editing'` - Full editing - - +Irreversible. The instance cannot be used after this. ```javascript -editor.setDocumentMode('suggesting'); +editor.destroy(); ``` -## Command Methods - -### `chain` - -Create a command chain. - -**Returns:** `ChainedCommands` - Chainable command object +### `focus` / `blur` ```javascript -editor.chain() - .focus() - .selectAll() - .toggleBold() - .run(); +editor.focus(); +editor.blur(); ``` -### `can` +### `setEditable` -Check if commands can run without executing. +```javascript +editor.setEditable(false); // Read-only +editor.setEditable(true); // Editable +``` -**Returns:** `Commands` - Commands in check mode +### `setDocumentMode` ```javascript -if (editor.can().toggleBold()) { - // Bold button should be enabled -} +editor.setDocumentMode('editing'); // Full editing +editor.setDocumentMode('suggesting'); // Track changes +editor.setDocumentMode('viewing'); // Read-only ``` -### Direct Commands +## Commands -Access all commands directly. +All commands are accessed via `editor.commands`: ```javascript +// Formatting editor.commands.toggleBold(); +editor.commands.toggleItalic(); +editor.commands.toggleUnderline(); + +// Tables editor.commands.insertTable({ rows: 3, cols: 3 }); + +// Selection editor.commands.setTextSelection({ from: 10, to: 20 }); +editor.commands.selectAll(); ``` ### `insertContent` -Insert content into the document with automatic format detection. +Insert content with automatic format detection. - Content to insert (HTML, Markdown, text, or JSON) + Content to insert - Insert options - - Content format: 'html', 'markdown', 'text', or 'schema' - - - `'html'` - HTML string (AI-generated, web content) - - `'markdown'` - Markdown text - - `'text'` - Plain text - - `'schema'` - ProseMirror JSON + `'html'`, `'markdown'`, `'text'`, or `'schema'` - Where to insert (defaults to current position) - - - Update selection after insert + Insert position (defaults to cursor) -**Returns:** `boolean` - Success status - ```javascript -// Insert HTML from AI -editor.commands.insertContent(htmlContent, { - contentType: 'html' -}); - -// Insert Markdown -editor.commands.insertContent(markdownText, { - contentType: 'markdown' -}); - -// Insert plain text -editor.commands.insertContent('Simple text', { - contentType: 'text' -}); - -// Insert structured JSON -editor.commands.insertContent(documentSchema, { - contentType: 'schema' -}); - -// Insert at specific position -editor.commands.insertContent(content, { - contentType: 'html', - position: { from: 100, to: 150 } -}); +editor.commands.insertContent(htmlContent, { contentType: 'html' }); +editor.commands.insertContent(markdownText, { contentType: 'markdown' }); +editor.commands.insertContent('Plain text', { contentType: 'text' }); ``` -**AI Integration Example:** -```javascript -// From any LLM -const aiResponse = await llm.generate(prompt); -editor.commands.insertContent(aiResponse, { - contentType: 'html' // LLMs typically output HTML or Markdown -}); -``` +HTML and Markdown inline styles are stripped on import to ensure Word compatibility. - -When importing HTML or Markdown, all inline styles are removed to ensure Word compatibility. - +## Document metadata -## Content Manipulation - -### `replaceContent` - -Replace entire editor content. - - - ProseMirror JSON content - +### `getMetadata` ```javascript -editor.replaceContent(newJsonContent); +const { documentGuid, isModified, version } = editor.getMetadata(); ``` -### `replaceNodeWithHTML` +### `getDocumentIdentifier` -Replace specific node with HTML. - - - ProseMirror node to replace - - - - HTML replacement - +Get a stable identifier (GUID or content hash). ```javascript -const tableNode = editor.getNodesOfType('table')[0]; -editor.replaceNodeWithHTML(tableNode, '...
'); +const id = await editor.getDocumentIdentifier(); ``` -### `replaceFile` - -Replace current DOCX file. - - - New DOCX file - - -**Returns:** `Promise` +### `isDocumentModified` ```javascript -await editor.replaceFile(newDocxFile); +if (editor.isDocumentModified()) { + // Prompt user to save +} ``` -## Annotation Methods - These methods are available with the [field-annotation](/extensions/field-annotation) extension. +## Schema -### `annotate` +### `getSchemaSummaryJSON` -Apply field annotations to document. - - - Annotation values - - - - Field ID - - - Field value - - - - - - Field IDs to hide - - - - Remove empty fields - +Generate a summary of the document schema. Useful for AI agents that need to understand the document structure. ```javascript -editor.annotate([ - { input_id: 'field1', input_value: 'John Doe' }, - { input_id: 'field2', input_value: 'CEO' } -], ['field3'], true); +const summary = await editor.getSchemaSummaryJSON(); ``` -### `previewAnnotations` +## Position & coordinates -Preview annotations (reversible). +### `getElementAtPos` - - Annotation values - +Get the DOM element at a document position. - - Field IDs to hide + + Document position ```javascript -editor.previewAnnotations(values, hiddenIds); -``` - -### `closePreview` - -Revert annotation preview. - -```javascript -editor.closePreview(); +const element = editor.getElementAtPos(42); ``` -## Search Methods - -### `search` - -Search for text or regex. - - - Search query - - -**Returns:** `Array` - Search matches - -```javascript -const results = editor.commands.search('hello'); -const results = editor.commands.search(/\d{3}-\d{2}-\d{4}/gi); // SSN pattern -``` - -```javascript -const matches = editor.commands.search('hello'); -editor.commands.goToSearchResult(matches[0]); -``` - -## Utility Methods - ### `getNodesOfType` -Get all nodes of specific type. - - - Node type name - - -**Returns:** `Array` - Matching nodes +Get all nodes of a specific type. ```javascript const tables = editor.getNodesOfType('table'); +const paragraphs = editor.getNodesOfType('paragraph'); ``` ### `isActive` -Check if node or mark is active. - - - Node/mark name or attributes - - - - Additional attributes to check - - -**Returns:** `boolean` - Whether active +Check if a node or mark is active. ```javascript editor.isActive('bold'); editor.isActive('heading', { level: 2 }); -editor.isActive({ textAlign: 'center' }); ``` ### `getAttributes` -Get attributes of active node or mark. - - - Name or type to get attributes for - - -**Returns:** `Object` - Attributes +Get attributes of the active node or mark. ```javascript const attrs = editor.getAttributes('link'); console.log(attrs.href); ``` -### `getElementAtPos` - -Available in versions greater than 1.5.0-next.1. - -Get the DOM element at a document position. In presentation/layout mode, returns the painted element from the rendered page. - - - Document position - - - - Configuration options (presentation mode only) - - - - Rebuild the DOM position index before lookup - - - Use coordinate-based lookup (`elementFromPoint`) if index lookup fails - - - +## Page & layout -**Returns:** `HTMLElement | null` - DOM element at position, or `null` if unavailable +### `getPageStyles` ```javascript -// Get element at cursor position -const element = editor.getElementAtPos(editor.state.selection.from); - -// With fallback for edge cases -const element = editor.getElementAtPos(pos, { fallbackToCoords: true }); +const styles = editor.getPageStyles(); ``` - -**Virtualization:** In presentation mode with page virtualization enabled (default), elements on offscreen pages are not mounted in the DOM. If `getElementAtPos` returns `null`, scroll the position into view first: +### `updatePageStyle` ```javascript -editor.presentationEditor.scrollToPosition(pos); -const element = editor.getElementAtPos(pos); +editor.updatePageStyle({ + pageMargins: { top: '1in', bottom: '1in', left: '1in', right: '1in' } +}); ``` -To disable virtualization, use `layoutEngineOptions` when creating SuperDoc: +## Search ```javascript -const superdoc = new SuperDoc({ - layoutEngineOptions: { - virtualization: { enabled: false } - } -}); -``` - +const results = editor.commands.search('hello'); +const results = editor.commands.search(/\d{3}-\d{4}/gi); - -In presentation mode, this method only works in body mode. It returns `null` when editing headers or footers. - +editor.commands.goToSearchResult(results[0]); +``` ## Properties - - ProseMirror EditorState - - - - ProseMirror EditorView - - - - ProseMirror Schema - - - - All available commands - - - - Extension helper methods - - - - Extension storage - - - - Whether editor is editable - - - - Whether editor is destroyed - - - - Whether editor has focus - +| Property | Type | Description | +|---|---|---| +| `lifecycleState` | `string` | `'initialized'`, `'documentLoading'`, `'ready'`, `'saving'`, `'closed'`, `'destroyed'` | +| `isEditable` | `boolean` | Whether editor accepts input | +| `isDestroyed` | `boolean` | Whether editor has been destroyed | +| `isFocused` | `boolean` | Whether editor has focus | +| `docChanged` | `boolean` | Whether any edits have been made | +| `sourcePath` | `string \| null` | Source file path (null if opened from Blob) | diff --git a/apps/docs/core/supereditor/overview.mdx b/apps/docs/core/supereditor/overview.mdx index c27f4f5c8d..4ecc631867 100644 --- a/apps/docs/core/supereditor/overview.mdx +++ b/apps/docs/core/supereditor/overview.mdx @@ -4,6 +4,10 @@ sidebarTitle: Overview keywords: "supereditor class, prosemirror docx, tiptap alternative, editor commands, document manipulation api" --- + +**Looking for programmatic document access?** The [Document API](/document-api/overview) is coming soon with a stable, engine-agnostic interface for querying and manipulating documents. + + SuperEditor is the core DOCX editing engine that powers SuperDoc. Use it directly when you need fine-grained control. ## When to use SuperEditor vs SuperDoc @@ -22,66 +26,33 @@ SuperEditor is the core DOCX editing engine that powers SuperDoc. Use it directl - [Headless/server-side processing](/core/supereditor/configuration#headless-converter-nodejs) - Custom extension development -## Quick Start +## Quick start ```javascript import "superdoc/style.css"; -import { Editor, getStarterExtensions } from "superdoc/super-editor"; - -async function initEditor() { - // 1. Load and prepare the DOCX file - const response = await fetch("/document.docx"); - const blob = await response.blob(); - const file = new File([blob], "document.docx", { - type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - }); - - // 2. Parse the DOCX file - const [content, media, mediaFiles, fonts] = await Editor.loadXmlData(file); - - // 3. Create the editor - const editor = new Editor({ - mode: "docx", - documentMode: "editing", - element: document.getElementById("editor"), - documentId: "doc-123", - extensions: getStarterExtensions(), - fileSource: file, - content, - media, - mediaFiles, - fonts, - }); -} - -initEditor(); -``` +import { Editor } from "superdoc/super-editor"; -## Key Initialization Steps +// Open a DOCX file in the browser +const response = await fetch("/document.docx"); +const file = await response.blob(); + +const editor = await Editor.open(file, { + element: document.getElementById("editor"), + documentMode: "editing", +}); +``` -1. **Import styles and modules** - Import the CSS and the Editor class with extensions -2. **Parse the DOCX** - Use `Editor.loadXmlData(file)` to extract content, media, and fonts -3. **Create the Editor** - Pass all parsed data plus required options like `extensions` +## Key initialization steps -## Direct ProseMirror access +1. **Import styles and the Editor class** +2. **Call `Editor.open()`** - Pass a file source and options. The editor handles parsing, extensions, and mounting automatically. -SuperEditor gives you full ProseMirror access: +## Components -```javascript -// Access ProseMirror directly -editor.view; // EditorView -editor.state; // EditorState -editor.schema; // Schema -editor.commands; // All commands - -// Do anything ProseMirror can do -editor.state.doc.forEach((node) => { - console.log(node.type.name); -}); -``` +The `SuperEditor` Vue component wraps the `Editor` class with reactive props and events. Use it in Vue apps for automatic lifecycle management. For other frameworks, use `Editor.open()` directly. ## API structure - **[Configuration](/core/supereditor/configuration)** - Initialization options -- **[Methods](/core/supereditor/methods)** - Control the editor -- **[Hooks](/core/supereditor/hooks)** - React to changes +- **[Methods](/core/supereditor/methods)** - Control the editor and access properties +- **[Events](/core/supereditor/events)** - React to changes diff --git a/apps/docs/docs.json b/apps/docs/docs.json index 93f8c18b81..51318e68d1 100644 --- a/apps/docs/docs.json +++ b/apps/docs/docs.json @@ -49,24 +49,17 @@ "getting-started/introduction", "getting-started/ai-agents", "getting-started/installation", - "getting-started/configuration", - "getting-started/import-export", - "getting-started/fonts", { "group": "Frameworks", "pages": [ "getting-started/frameworks/react", "getting-started/frameworks/vue", - "getting-started/frameworks/vanilla-js", "getting-started/frameworks/angular", - "getting-started/frameworks/nextjs", - "getting-started/frameworks/svelte", - "getting-started/frameworks/php", - "getting-started/frameworks/nuxt", - "getting-started/frameworks/ruby-on-rails", - "getting-started/frameworks/blazor" + "getting-started/frameworks/vanilla-js" ] - } + }, + "getting-started/import-export", + "getting-started/fonts" ] }, { @@ -74,22 +67,22 @@ "pages": [ { "group": "SuperDoc", + "tag": "UDPATED", "pages": [ "core/superdoc/overview", "core/superdoc/configuration", "core/superdoc/methods", - "core/superdoc/events", - "core/superdoc/properties", - "core/superdoc/types" + "core/superdoc/events" ] }, { "group": "SuperEditor", + "tag": "UDPATED", "pages": [ "core/supereditor/overview", "core/supereditor/configuration", "core/supereditor/methods", - "core/supereditor/hooks" + "core/supereditor/events" ] } ] @@ -99,25 +92,6 @@ "tag": "SOON", "pages": ["document-api/overview"] }, - { - "group": "AI", - "tag": "NEW", - "pages": [ - { - "group": "AI Actions", - "pages": [ - "ai/ai-actions/overview", - "ai/ai-actions/configuration", - "ai/ai-actions/methods", - "ai/ai-actions/hooks" - ] - }, - { - "group": "AI Builder", - "pages": ["ai/ai-builder/overview"] - } - ] - }, { "group": "Modules", "pages": [ @@ -127,44 +101,34 @@ "pages": [ "modules/collaboration/overview", "modules/collaboration/quickstart", - "modules/collaboration/configuration", - { - "group": "Cloud Providers", - "pages": ["modules/collaboration/cloud/liveblocks", "modules/collaboration/cloud/tiptap-cloud"] - }, - { - "group": "Self-Hosted", - "pages": [ - "modules/collaboration/self-hosted/overview", - "modules/collaboration/self-hosted/superdoc-yjs", - "modules/collaboration/self-hosted/hocuspocus", - "modules/collaboration/self-hosted/y-sweet" - ] - } + "modules/collaboration/configuration" ] }, "modules/comments", - "modules/toolbar" + "modules/toolbar", + "modules/context-menu" ] }, { "group": "Extensions", "pages": [ "extensions/overview", - "extensions/creating-extensions", { "group": "All", "pages": [ "extensions/block-node", "extensions/bold", + "extensions/bookmarks", "extensions/bullet-list", "extensions/color", "extensions/content-block", "extensions/custom-selection", "extensions/document", + "extensions/document-index", "extensions/dropcursor", "extensions/font-family", "extensions/font-size", + "extensions/footnote", "extensions/format-commands", "extensions/gapcursor", "extensions/heading", @@ -182,6 +146,7 @@ "extensions/ordered-list", "extensions/page-number", "extensions/paragraph", + "extensions/permission-ranges", "extensions/placeholder", "extensions/popover-plugin", "extensions/run-item", @@ -195,6 +160,7 @@ "extensions/table", "extensions/table-cell", "extensions/table-header", + "extensions/table-of-contents", "extensions/table-row", "extensions/text-align", "extensions/text-indent", @@ -221,7 +187,6 @@ }, { "group": "Template Builder", - "tag": "NEW", "pages": [ "solutions/template-builder/introduction", "solutions/template-builder/quickstart", @@ -232,21 +197,32 @@ ] }, { - "group": "Resources", - "pages": ["resources/guides", "resources/license"] - } - ] - }, - { - "tab": "Guides", - "groups": [ - { - "group": "General", - "pages": ["guides/general/storage", "guides/general/accessibility", "guides/general/security"] + "group": "Guides", + "pages": [ + "guides/general/storage", + { + "group": "Collaboration", + "pages": [ + "guides/collaboration/liveblocks", + "guides/collaboration/tiptap-cloud", + "guides/collaboration/superdoc-yjs", + "guides/collaboration/hocuspocus", + "guides/collaboration/y-sweet" + ] + }, + { + "group": "Migration", + "pages": [ + "guides/migration/prosemirror", + "guides/migration/breaking-changes-v1", + "guides/migration/typescript-migration" + ] + } + ] }, { - "group": "Migration", - "pages": ["guides/migration/prosemirror", "guides/breaking-changes-v1", "guides/typescript-migration"] + "group": "Resources", + "pages": ["guides/general/accessibility", "guides/general/security", "resources/license"] } ] }, @@ -290,7 +266,7 @@ "links": [ { "type": "button", - "href": "https://github.com/Harbour-Enterprises/SuperDoc", + "href": "https://github.com/superdoc-dev/superdoc", "label": "", "icon": "github" }, @@ -303,6 +279,18 @@ ] }, "redirects": [ + { + "source": "/core/superdoc/properties", + "destination": "/core/superdoc/methods#properties" + }, + { + "source": "/core/superdoc/types", + "destination": "/core/superdoc/methods#typescript-types" + }, + { + "source": "/core/supereditor/hooks", + "destination": "/core/supereditor/events" + }, { "source": "/guide/quick-start", "destination": "/getting-started/installation" @@ -373,11 +361,43 @@ }, { "source": "/modules/collaboration/backend", - "destination": "/modules/collaboration/self-hosted/overview" + "destination": "/modules/collaboration/configuration" }, { "source": "/modules/collaboration/client", "destination": "/modules/collaboration/configuration" + }, + { + "source": "/modules/collaboration/cloud/liveblocks", + "destination": "/guides/collaboration/liveblocks" + }, + { + "source": "/modules/collaboration/cloud/tiptap-cloud", + "destination": "/guides/collaboration/tiptap-cloud" + }, + { + "source": "/modules/collaboration/self-hosted/superdoc-yjs", + "destination": "/guides/collaboration/superdoc-yjs" + }, + { + "source": "/modules/collaboration/self-hosted/hocuspocus", + "destination": "/guides/collaboration/hocuspocus" + }, + { + "source": "/modules/collaboration/self-hosted/y-sweet", + "destination": "/guides/collaboration/y-sweet" + }, + { + "source": "/modules/collaboration/self-hosted/overview", + "destination": "/guides/collaboration/self-hosted-overview" + }, + { + "source": "/guides/breaking-changes-v1", + "destination": "/guides/migration/breaking-changes-v1" + }, + { + "source": "/guides/typescript-migration", + "destination": "/guides/migration/typescript-migration" } ], "integrations": { diff --git a/apps/docs/document-api/overview.mdx b/apps/docs/document-api/overview.mdx index a73a924e4d..f786ba50d4 100644 --- a/apps/docs/document-api/overview.mdx +++ b/apps/docs/document-api/overview.mdx @@ -26,7 +26,7 @@ This works, but: - Requires understanding ProseMirror internals - Tightly coupled to the editor implementation -## What's Coming +## What's coming The Document API provides a stable, high-level interface: @@ -53,9 +53,9 @@ doc.replace(paragraphs[0], { text: 'New content' }); -## Feature Preview +## Feature preview -### Querying Content +### Querying content Find any content in your document: @@ -76,7 +76,7 @@ const signatures = doc.query({ }); ``` -### Making Changes +### Making changes Modify documents with a clean API: @@ -91,7 +91,7 @@ doc.insert(address, { type: 'paragraph', text: 'New paragraph' }); doc.delete(address); ``` -### Working with Tables +### Working with tables First-class table operations: @@ -117,9 +117,9 @@ doc.table(tableAddress).cell(1, 2).replace({ text: 'New value' });
-## Stay Updated +## Stay updated -Join our Discord to get notified when Document API launches: +Join Discord to get notified when Document API launches: Get early access and share feedback diff --git a/apps/docs/extensions/block-node.mdx b/apps/docs/extensions/block-node.mdx index 170dfd6437..2da5a9475a 100644 --- a/apps/docs/extensions/block-node.mdx +++ b/apps/docs/extensions/block-node.mdx @@ -187,7 +187,7 @@ Block node information object -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/bold.mdx b/apps/docs/extensions/bold.mdx index 333e3ee63e..f60499821c 100644 --- a/apps/docs/extensions/bold.mdx +++ b/apps/docs/extensions/bold.mdx @@ -8,23 +8,33 @@ import Description from '/snippets/extensions/bold.mdx' -## Options +## Commands -Configure the extension behavior: +### `setBold` - - HTML attributes for the strong element - +Apply bold formatting to the current selection. -## Attributes +```javascript +editor.commands.setBold() +``` -Node attributes that can be set and retrieved: +### `unsetBold` - - Bold weight value ('0' renders as normal) - +Remove bold formatting from the current selection. -## Keyboard Shortcuts +```javascript +editor.commands.unsetBold() +``` + +### `toggleBold` + +Toggle bold formatting on the current selection. + +```javascript +editor.commands.toggleBold() +``` + +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| @@ -32,7 +42,7 @@ Node attributes that can be set and retrieved: | toggleBold() | `⌘/Ctrl-B` | Toggle bold formatting (uppercase) | -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/bookmarks.mdx b/apps/docs/extensions/bookmarks.mdx new file mode 100644 index 0000000000..7fd120f68e --- /dev/null +++ b/apps/docs/extensions/bookmarks.mdx @@ -0,0 +1,68 @@ +--- +title: Bookmarks extension +sidebarTitle: "Bookmarks" +keywords: "Bookmarks extension, superdoc Bookmarks, word Bookmarks, document Bookmarks, docx Bookmarks" +--- + +import Description from '/snippets/extensions/bookmarks.mdx' + + + +## Commands + +### `insertBookmark` + +Insert a bookmark at the current cursor position. Bookmarks are invisible navigation anchors used for cross-references and document navigation. + +**Example:** + +```javascript +editor.commands.insertBookmark({ name: 'chapter1' }) +editor.commands.insertBookmark({ name: 'introduction', id: 'intro-001' }) +``` + +**Parameters:** + + + Object with `name` (required bookmark name) and optional `id` (unique identifier) + + +### `goToBookmark` + +Navigate to a bookmark by name. Scrolls the document to the bookmark position. + +**Example:** + +```javascript +editor.commands.goToBookmark('chapter1') +``` + +**Parameters:** + + + Bookmark name to navigate to + + +## Attributes + +### BookmarkStart + + + Bookmark name for cross-references and navigation + + + + Unique identifier for the bookmark + + +### BookmarkEnd + + + Identifier matching the corresponding bookmarkStart + + +## Source code + +import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' + + diff --git a/apps/docs/extensions/bullet-list.mdx b/apps/docs/extensions/bullet-list.mdx index 7cabcb11ae..66b473337b 100644 --- a/apps/docs/extensions/bullet-list.mdx +++ b/apps/docs/extensions/bullet-list.mdx @@ -1,82 +1,43 @@ --- -title: BulletList extension +title: Bullet list sidebarTitle: "Bullet List" -keywords: "BulletList extension, superdoc BulletList, word BulletList, document BulletList, docx BulletList" +keywords: "bullet list, superdoc bullet list, word bullet list, document bullet list, docx bullet list" --- import Description from '/snippets/extensions/bullet-list.mdx' -## Options - -Configure the extension behavior: - - - Name of the list item node type - - - - HTML attributes for the ul element - - - - Whether to preserve attributes when splitting - - - - Whether to preserve marks when splitting - - -**Example:** - -```javascript -const ConfiguredBulletList = BulletList.configure({ - itemTypeName: 'customItem', - keepMarks: false -}); - -new SuperDoc({ - selector: '#editor', - document: 'document.docx', - editorExtensions: [ConfiguredBulletList] -}); -``` - -## Attributes - -Node attributes that can be set and retrieved: - - - List style type for this list - + +Bullet list functionality is part of the [Paragraph extension](/extensions/paragraph). There is no separate bullet list extension. + ## Commands ### `toggleBulletList` -Toggle a bullet list at the current selection - - -Converts selected paragraphs to list items or removes list formatting - +Toggle bullet list formatting on the current selection. Converts selected paragraphs to list items or removes list formatting. **Example:** ```javascript -// Toggle bullet list on selected text editor.commands.toggleBulletList() ``` -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| | toggleBulletList() | `⌘/Ctrl-Shift-8` | Toggle bullet list | +| (indent) | `Tab` | Increase list indentation | +| (outdent) | `Shift-Tab` | Decrease list indentation | + +## Input rules +Type `- `, `* `, or `+ ` followed by a space to start a bullet list automatically. -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' - + diff --git a/apps/docs/extensions/color.mdx b/apps/docs/extensions/color.mdx index 6e6e61a65e..9fe416b684 100644 --- a/apps/docs/extensions/color.mdx +++ b/apps/docs/extensions/color.mdx @@ -68,7 +68,7 @@ editor.commands.unsetColor() Accepts hex colors (#ff0000), rgb(255,0,0), or named colors (red) -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/comments.mdx b/apps/docs/extensions/comments.mdx index 24c9c97eab..4932c9efb5 100644 --- a/apps/docs/extensions/comments.mdx +++ b/apps/docs/extensions/comments.mdx @@ -1,13 +1,13 @@ --- -title: Comments Extension +title: Comments extension sidebarTitle: Comments --- -The Comments extension enables Word-style commenting with threads, replies, and resolution. +The Comments extension adds Word-style commenting with threads, replies, and resolution. ## Usage -Comments work through the module configuration: +Configure comments through the modules option: ```javascript modules: { @@ -20,44 +20,107 @@ modules: { ## Commands +### `addComment` + +Add a comment to the current text selection. Requires text to be selected. + ```javascript -// Add comment at selection -editor.commands.insertComment({ - content: 'Please review' -}); +// Simple text comment +editor.commands.addComment('Please review this section') + +// With options +editor.commands.addComment({ + content: 'Please review', + author: 'Jane Smith', + authorEmail: 'jane@example.com', + isInternal: false +}) +``` + +**Parameters:** + + + Comment text, or an options object with `content`, `author`, `authorEmail`, `authorImage`, and `isInternal` fields + -// Work with comments -editor.commands.replyToComment(commentId, { content: 'Done' }); -editor.commands.resolveComment(commentId); -editor.commands.deleteComment(commentId); +### `addCommentReply` -// Navigate -editor.commands.goToNextComment(); -editor.commands.goToPreviousComment(); +Add a reply to an existing comment thread. + +```javascript +editor.commands.addCommentReply({ + parentId: 'comment-123', + content: 'Done, updated the wording.' +}) ``` -## Events +**Parameters:** + + + Object with `parentId` (required), `content`, `author`, `authorEmail`, `authorImage` + + +### `removeComment` + +Remove a comment and its highlight marks from the document. ```javascript -superdoc.on('commentsUpdate', ({ type, comment }) => { - switch(type) { - case 'add': // Comment created - case 'update': // Comment edited - case 'deleted': // Comment removed - case 'resolved': // Comment resolved - } -}); +editor.commands.removeComment({ commentId: 'abc-123' }) ``` -## Working with comment data +**Parameters:** + + + Object with `commentId` and/or `importedId` + + +### `resolveComment` + +Resolve a comment. Removes the highlight but preserves positional anchors for export. ```javascript -// Access all comments -const comments = editor.storage.comments.items; +editor.commands.resolveComment({ commentId: 'abc-123' }) +``` + +**Parameters:** + + + Object with `commentId` + + +### `setActiveComment` -// Filter comments -const active = comments.filter(c => !c.resolved); -const byUser = comments.filter(c => c.user.email === email); +Set the active/selected comment thread by ID. + +```javascript +editor.commands.setActiveComment({ commentId: 'abc-123' }) +``` + +### `setCommentInternal` + +Toggle whether a comment is internal (private) or external. + +```javascript +editor.commands.setCommentInternal({ + commentId: 'abc-123', + isInternal: true +}) +``` + +### `setCursorById` + +Move the cursor to the start of a comment's range. Also works for tracked change IDs. + +```javascript +editor.commands.setCursorById('abc-123') +``` + +## Events + +```javascript +superdoc.on('commentsUpdate', ({ type, comment }) => { + // type: 'ADD' | 'deleted' | 'SELECTED' +}); ``` ## Export behavior @@ -65,17 +128,14 @@ const byUser = comments.filter(c => c.user.email === email); Comments export to DOCX as native Word comments: ```javascript -// Include comments await superdoc.export({ commentsType: 'external' }); -// Clean export +// Without comments await superdoc.export({ commentsType: 'clean' }); ``` -## Styling +## Source code -```css -.comment-mark { background: #fff3cd; } -.comment-mark.resolved { opacity: 0.6; } -.comment-mark.active { background: #ffd700; } -``` +import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' + + diff --git a/apps/docs/extensions/content-block.mdx b/apps/docs/extensions/content-block.mdx index 1d2128efd9..3d03b712fa 100644 --- a/apps/docs/extensions/content-block.mdx +++ b/apps/docs/extensions/content-block.mdx @@ -107,7 +107,7 @@ Content block configuration -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/creating-extensions.mdx b/apps/docs/extensions/creating-extensions.mdx index af7ae4382f..bbcee0ac32 100644 --- a/apps/docs/extensions/creating-extensions.mdx +++ b/apps/docs/extensions/creating-extensions.mdx @@ -8,7 +8,7 @@ Create extensions to add custom features to SuperDoc. ## Basic extension ```javascript -import { Extensions } from '@harbour-enterprises/superdoc'; +import { Extensions } from 'superdoc'; const { Extension } = Extensions; const MyExtension = Extension.create({ @@ -34,7 +34,7 @@ editor.commands.myCommand(); For document elements: ```javascript -import { Extensions } from '@harbour-enterprises/superdoc'; +import { Extensions } from 'superdoc'; const { Node } = Extensions; const CustomBlock = Node.create({ @@ -56,7 +56,7 @@ const CustomBlock = Node.create({ For inline formatting: ```javascript -import { Extensions } from '@harbour-enterprises/superdoc'; +import { Extensions } from 'superdoc'; const { Mark } = Extensions; const Highlight = Mark.create({ @@ -145,6 +145,87 @@ const ConfigurableExt = Extension.create({ ConfigurableExt.configure({ color: '#FF0000' }); ``` +## Type-safe factories + +Use `defineNode` and `defineMark` instead of `Node.create()` / `Mark.create()` for typed attributes: + +```typescript +import { defineNode, defineMark } from 'superdoc/super-editor'; + +const CustomBlock = defineNode({ + name: 'customBlock', + group: 'block', + content: 'inline*', + + addAttributes() { + return { + level: { default: 1 }, + collapsed: { default: false }, + }; + }, + + parseHTML() { + return [{ tag: 'div[data-custom]' }]; + }, + + renderHTML({ HTMLAttributes }) { + return ['div', { 'data-custom': '' }, 0]; + }, +}); + +const CustomMark = defineMark({ + name: 'customMark', + + addAttributes() { + return { + color: { default: null }, + }; + }, +}); +``` + +With TypeScript generics you get full attribute autocompletion: + +```typescript +interface CustomBlockAttrs { + level: number; + collapsed: boolean; +} + +const CustomBlock = defineNode<{}, {}, CustomBlockAttrs>({ + name: 'customBlock', + // attrs are now typed as CustomBlockAttrs +}); +``` + +## Type guards + +Use type guards when traversing the document to get typed node/mark attributes: + +```typescript +import { isNodeType, assertNodeType, isMarkType } from 'superdoc/super-editor'; + +// Type guard — narrows the type in if blocks +editor.state.doc.descendants((node) => { + if (isNodeType(node, 'paragraph')) { + // node.attrs is now typed as ParagraphAttrs + console.log(node.attrs.paragraphProperties?.styleId); + } +}); + +// Assertion — throws if type doesn't match +const node = state.doc.nodeAt(pos); +assertNodeType(node, 'table'); +// node.attrs is now typed as TableAttrs + +// Mark type guard +for (const mark of node.marks) { + if (isMarkType(mark, 'bold')) { + // mark.attrs is typed + } +} +``` + ## Using your extension ```javascript diff --git a/apps/docs/extensions/custom-selection.mdx b/apps/docs/extensions/custom-selection.mdx index 19b5748656..b65016279d 100644 --- a/apps/docs/extensions/custom-selection.mdx +++ b/apps/docs/extensions/custom-selection.mdx @@ -49,7 +49,7 @@ Selection state -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/document-index.mdx b/apps/docs/extensions/document-index.mdx new file mode 100644 index 0000000000..570a902445 --- /dev/null +++ b/apps/docs/extensions/document-index.mdx @@ -0,0 +1,50 @@ +--- +title: Document Index extension +sidebarTitle: "Document Index" +keywords: "Document Index extension, superdoc Document Index, word Document Index, document index, docx index, index entry" +--- + +import Description from '/snippets/extensions/document-index.mdx' + + + + +Document indexes and index entries are managed automatically during Word document import and export. There are no commands to programmatically create or update indexes. + + +## How it works + +The document index system consists of two node types: + +- **Index block** — A block node that contains the rendered index (alphabetical listing of terms with page references) +- **Index entry** — An invisible inline marker placed throughout the document text to mark terms for inclusion in the index + +## Word export + +Indexes export as Word field codes: + +```xml + + + + INDEX \l "1" + + + + + + + + + XE "Primary Entry" + + + + +``` + +## Source code + +import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' + + diff --git a/apps/docs/extensions/document-section.mdx b/apps/docs/extensions/document-section.mdx index 9553b375e2..4386768b78 100644 --- a/apps/docs/extensions/document-section.mdx +++ b/apps/docs/extensions/document-section.mdx @@ -1,5 +1,5 @@ --- -title: Document Section Extension +title: Document Section extension sidebarTitle: Document Section --- @@ -10,26 +10,14 @@ Encapsulate and manage discrete parts of documents. Legal clauses stay locked wh Included by default in SuperDoc. ```javascript -import { DocumentSection } from '@harbour-enterprises/superdoc/extensions'; -``` - -## Configuration - -```javascript -// Configure during initialization -DocumentSection.configure({ - // Configuration options - allowNested: false, // Don't allow nested sections - maxSize: 100000, // Maximum characters per section - defaultLocked: false // Default lock state -}); +import { DocumentSection } from 'superdoc/extensions'; ``` ## Commands -All commands available on `editor.commands`: +### `createDocumentSection` -### Section Creation +Create a new document section. ```javascript editor.commands.createDocumentSection({ @@ -41,39 +29,54 @@ editor.commands.createDocumentSection({ }) ``` -### Section Manipulation +### `removeSectionAtSelection` + +Remove the section at the current cursor position. ```javascript editor.commands.removeSectionAtSelection() +``` + +### `removeSectionById` + +Remove a section by its ID. + +```javascript editor.commands.removeSectionById('legal-1') +``` + +### `lockSectionById` + +Lock a section to prevent editing. + +```javascript editor.commands.lockSectionById('legal-1') -editor.commands.updateSectionById({ - id: 'legal-1', - html: '

Updated...

', - attrs: { title: 'New Title' } -}) ``` -## Helper Functions +### `updateSectionById` -Import helpers: +Update a section's content or attributes. ```javascript -import { SectionHelpers } from '@harbour-enterprises/superdoc'; +editor.commands.updateSectionById({ + id: 'legal-1', + html: '

Updated...

', + attrs: { title: 'New Title' } +}) ``` -### Available Helpers +## Helpers ```javascript // Get all sections -const sections = SectionHelpers.getAllSections(editor); +const sections = editor.helpers.documentSection.getAllSections(editor); // Export sections -const html = SectionHelpers.exportSectionsToHTML(editor); -const json = SectionHelpers.exportSectionsToJSON(editor); +const html = editor.helpers.documentSection.exportSectionsToHTML(editor); +const json = editor.helpers.documentSection.exportSectionsToJSON(editor); -// Create linked editor -const childEditor = SectionHelpers.getLinkedSectionEditor( +// Create a linked editor for a section +const childEditor = editor.helpers.documentSection.getLinkedSectionEditor( 'section-id', { element: '#editor' }, parentEditor @@ -82,8 +85,6 @@ const childEditor = SectionHelpers.getLinkedSectionEditor( ## Attributes -Section nodes have these attributes: - | Attribute | Type | Default | Description | |-----------|------|---------|-------------| | `id` | string/number | auto | Unique identifier | @@ -92,69 +93,7 @@ Section nodes have these attributes: | `sectionType` | string | '' | Business classification | | `isLocked` | boolean | false | Edit prevention | -## Events - -The extension emits these events: - -```javascript -editor.on('section:created', ({ section }) => { - console.log('Section created:', section.id); -}); - -editor.on('section:updated', ({ section, changes }) => { - console.log('Section updated:', section.id); -}); - -editor.on('section:removed', ({ sectionId }) => { - console.log('Section removed:', sectionId); -}); - -editor.on('section:locked', ({ sectionId, locked }) => { - console.log('Lock changed:', sectionId, locked); -}); -``` - -## Schema - -### Node Definition - -```javascript -{ - name: 'documentSection', - group: 'block', - content: 'block*', - atom: true, - isolating: true, - attrs: { - id: { default: null }, - title: { default: '' }, - description: { default: '' }, - sectionType: { default: '' }, - isLocked: { default: false } - } -} -``` - -### HTML Structure - -```html - -
-

Section content...

-
- - -
-
Terms & Conditions
-
-

Section content...

-
-
-``` - -## Word Export +## Word export Sections export as Word content controls: @@ -171,9 +110,9 @@ Sections export as Word content controls: ``` -## Common Patterns +## Common patterns -### Contract Structure +### Contract structure ```javascript const contractSections = [ @@ -191,105 +130,23 @@ contractSections.forEach(section => { }); ``` -### Role-Based Locking +### Role-based locking ```javascript function applyRolePermissions(userRole) { - const sections = SectionHelpers.getAllSections(editor); - + const sections = editor.helpers.documentSection.getAllSections(editor); + sections.forEach(({ node }) => { const { id, sectionType } = node.attrs; - + if (sectionType === 'legal' && userRole !== 'legal') { editor.commands.lockSectionById(id); - } else if (sectionType === 'pricing' && userRole === 'viewer') { - editor.commands.lockSectionById(id); } }); } ``` -### Section Templates - -```javascript -const templates = { - header: { - title: 'Document Header', - sectionType: 'header', - html: '

Agreement

Date: [DATE]

' - }, - legalTerms: { - title: 'Legal Terms', - sectionType: 'legal', - isLocked: true, - html: loadLegalTemplate() - } -}; - -function insertTemplate(templateId) { - const template = templates[templateId]; - editor.commands.createDocumentSection({ - ...template, - id: generateId() - }); -} -``` - -### Conditional Content - -```javascript -// Show/hide sections based on conditions -function updateSectionsForRegion(region) { - const sections = SectionHelpers.getAllSections(editor); - - sections.forEach(({ node, pos }) => { - if (node.attrs.sectionType === 'regional') { - if (!node.attrs.regions?.includes(region)) { - editor.commands.removeSectionById(node.attrs.id); - } - } - }); - - // Add region-specific sections - if (region === 'EU') { - editor.commands.createDocumentSection({ - id: 'gdpr', - title: 'GDPR Compliance', - sectionType: 'regional', - html: gdprTemplate - }); - } -} -``` - -## Limitations - -- Cannot nest sections -- Maximum 100K characters per section -- Locked sections still selectable -- Section IDs must be unique - -## Performance - -For documents with many sections: - -```javascript -// Batch updates -editor.chain() - .command(() => { - sections.forEach(s => { - editor.commands.updateSectionById(s); - }); - return true; - }) - .run(); - -// Lazy loading -const visibleSections = getVisibleSections(); -visibleSections.forEach(loadSectionContent); -``` - ## Related - [Field Annotation](/extensions/field-annotation) - Form fields -- [Table Extension](/extensions/table) - Tables \ No newline at end of file +- [Structured Content](/extensions/structured-content) - Structured content blocks diff --git a/apps/docs/extensions/document.mdx b/apps/docs/extensions/document.mdx index 5dee7ac4ac..d34b074827 100644 --- a/apps/docs/extensions/document.mdx +++ b/apps/docs/extensions/document.mdx @@ -40,8 +40,28 @@ Replaces all content with an empty paragraph editor.commands.clearDocument() ``` +### `setSectionPageMarginsAtSelection` -## Source Code +Set page margins for the section at the current cursor position. + +**Example:** + +```javascript +editor.commands.setSectionPageMarginsAtSelection({ + topInches: 1, + rightInches: 1, + bottomInches: 1, + leftInches: 1 +}) +``` + +**Parameters:** + + + Object with optional `topInches`, `rightInches`, `bottomInches`, `leftInches` (numbers in inches) + + +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/dropcursor.mdx b/apps/docs/extensions/dropcursor.mdx index 4e473db844..127fa070cd 100644 --- a/apps/docs/extensions/dropcursor.mdx +++ b/apps/docs/extensions/dropcursor.mdx @@ -43,7 +43,7 @@ new SuperDoc({ ``` -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/field-annotation.mdx b/apps/docs/extensions/field-annotation.mdx index 9378a1a42c..c64c56e48b 100644 --- a/apps/docs/extensions/field-annotation.mdx +++ b/apps/docs/extensions/field-annotation.mdx @@ -5,7 +5,7 @@ description: "Interactive form fields for documents. It can be used when variabl Available since v0.10.0 -Field Annotation use is not recommended because of its limited support for advanced document content (e.g., tables, advanced styling). We instead recommend using the more versatile [Structured Content Fields](/extensions/structured-content). +Field Annotation use is not recommended because of its limited support for advanced document content (e.g., tables, advanced styling). Use the more versatile [Structured Content Fields](/extensions/structured-content). ## Configuration @@ -13,16 +13,12 @@ description: "Interactive form fields for documents. It can be used when variabl Handle drops outside editor viewport - + CSS class for field styling - - Default field background color - - - - Maximum annotations per document + + Default field border color @@ -291,7 +287,8 @@ headerFooterAnnotations.forEach(({ node, pos }) => { Get all field annotations in the document ```javascript -import { getAllFieldAnnotations } from './fieldAnnotationHelpers'; +import { fieldAnnotationHelpers } from 'superdoc'; +const { getAllFieldAnnotations } = fieldAnnotationHelpers; const annotations = getAllFieldAnnotations(editor.state); console.log(`Document contains ${annotations.length} field annotations`); diff --git a/apps/docs/extensions/font-family.mdx b/apps/docs/extensions/font-family.mdx index 46a2765785..49cb73ee7b 100644 --- a/apps/docs/extensions/font-family.mdx +++ b/apps/docs/extensions/font-family.mdx @@ -68,7 +68,7 @@ editor.commands.unsetFontFamily() CSS font-family string (e.g., 'Arial', 'Times New Roman', 'sans-serif') -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/font-size.mdx b/apps/docs/extensions/font-size.mdx index 3166eca56e..44a0eead4b 100644 --- a/apps/docs/extensions/font-size.mdx +++ b/apps/docs/extensions/font-size.mdx @@ -92,7 +92,7 @@ Font size configuration Size with optional unit (e.g., '12pt', '16px', 14) -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/footnote.mdx b/apps/docs/extensions/footnote.mdx new file mode 100644 index 0000000000..6b95415148 --- /dev/null +++ b/apps/docs/extensions/footnote.mdx @@ -0,0 +1,36 @@ +--- +title: Footnote extension +sidebarTitle: "Footnote" +keywords: "Footnote extension, superdoc Footnote, word Footnote, document Footnote, docx Footnote" +--- + +import Description from '/snippets/extensions/footnote.mdx' + + + + +Footnote references are managed automatically during Word document import and export. There are no commands to programmatically create footnotes. + + +## Word export + +Footnote references export as native Word footnotes: + +```xml + + + + + + + + Footnote text content + + +``` + +## Source code + +import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' + + diff --git a/apps/docs/extensions/format-commands.mdx b/apps/docs/extensions/format-commands.mdx index 273830b320..e55b3756fc 100644 --- a/apps/docs/extensions/format-commands.mdx +++ b/apps/docs/extensions/format-commands.mdx @@ -66,7 +66,27 @@ Works like format painter - first click copies, second click applies editor.commands.copyFormat() ``` -## Keyboard Shortcuts +### `toggleMarkCascade` + +Toggle a mark type with cascade behavior, handling nested marks and negation attributes. Used internally by formatting extensions (bold, italic, etc.) but can be called directly for custom mark toggling. + +**Example:** + +```javascript +editor.commands.toggleMarkCascade('bold') +editor.commands.toggleMarkCascade('italic', { extendEmptyMarkRange: true }) +``` + +**Parameters:** + + + Name of the mark type to toggle + + + Options with `negationAttrs`, `isNegation`, `styleDetector`, and `extendEmptyMarkRange` + + +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| @@ -88,7 +108,7 @@ Stored format style -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/gapcursor.mdx b/apps/docs/extensions/gapcursor.mdx index fba8ad58cd..3f9b77e418 100644 --- a/apps/docs/extensions/gapcursor.mdx +++ b/apps/docs/extensions/gapcursor.mdx @@ -9,7 +9,7 @@ import Description from '/snippets/extensions/gapcursor.mdx' -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/heading.mdx b/apps/docs/extensions/heading.mdx index b450910f10..1fdba0d804 100644 --- a/apps/docs/extensions/heading.mdx +++ b/apps/docs/extensions/heading.mdx @@ -67,7 +67,7 @@ editor.commands.toggleHeading({ level: 3 }) Heading attributes including level -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| @@ -79,7 +79,7 @@ editor.commands.toggleHeading({ level: 3 }) | toggleHeading() | `⌘/Ctrl-Alt-6` | Toggle heading level 6 | -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/highlight.mdx b/apps/docs/extensions/highlight.mdx index 2932ea699e..4e9651650e 100644 --- a/apps/docs/extensions/highlight.mdx +++ b/apps/docs/extensions/highlight.mdx @@ -63,14 +63,14 @@ Toggle highlight formatting editor.commands.toggleHighlight() ``` -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| | toggleHighlight() | `⌘/Ctrl-Shift-h` | Toggle highlighted formatting | -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/history.mdx b/apps/docs/extensions/history.mdx index b518ac60e5..fa702d88dd 100644 --- a/apps/docs/extensions/history.mdx +++ b/apps/docs/extensions/history.mdx @@ -50,7 +50,7 @@ Only available after an undo action editor.commands.redo() ``` -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| @@ -59,7 +59,7 @@ editor.commands.redo() | redo() | `⌘/Ctrl-y` | Redo last action (alternative) | -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/image.mdx b/apps/docs/extensions/image.mdx index 6deb90ef53..ad873e35f3 100644 --- a/apps/docs/extensions/image.mdx +++ b/apps/docs/extensions/image.mdx @@ -84,6 +84,14 @@ Node attributes that can be set and retrieved: Custom inline CSS styles + + Text wrapping configuration. The `type` property controls wrapping mode (e.g., `'Inline'`, `'Square'`, `'Tight'`, `'TopAndBottom'`, `'None'`). + + + + Transform data for rotation, flips, and size extension. Supports `rotation` (degrees), `flipH` (horizontal flip), `flipV` (vertical flip), and `sizeExtension` properties. + + ## Commands ### `setImage` @@ -185,7 +193,7 @@ Options for inserting an image -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/italic.mdx b/apps/docs/extensions/italic.mdx index 32190997f9..90ca736319 100644 --- a/apps/docs/extensions/italic.mdx +++ b/apps/docs/extensions/italic.mdx @@ -8,15 +8,33 @@ import Description from '/snippets/extensions/italic.mdx' -## Options +## Commands -Configure the extension behavior: +### `setItalic` - - HTML attributes for italic elements - +Apply italic formatting to the current selection. -## Keyboard Shortcuts +```javascript +editor.commands.setItalic() +``` + +### `unsetItalic` + +Remove italic formatting from the current selection. + +```javascript +editor.commands.unsetItalic() +``` + +### `toggleItalic` + +Toggle italic formatting on the current selection. + +```javascript +editor.commands.toggleItalic() +``` + +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| @@ -24,7 +42,7 @@ Configure the extension behavior: | toggleItalic() | `⌘/Ctrl-I` | Toggle italic formatting (uppercase) | -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/line-break.mdx b/apps/docs/extensions/line-break.mdx index caa56e5703..0cd41cf5ed 100644 --- a/apps/docs/extensions/line-break.mdx +++ b/apps/docs/extensions/line-break.mdx @@ -39,7 +39,7 @@ editor.commands.insertPageBreak() ``` -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/line-height.mdx b/apps/docs/extensions/line-height.mdx index 3963f345ae..c64810199c 100644 --- a/apps/docs/extensions/line-height.mdx +++ b/apps/docs/extensions/line-height.mdx @@ -1,68 +1,35 @@ --- -title: LineHeight extension +title: Line Height sidebarTitle: "Line Height" -keywords: "LineHeight extension, superdoc LineHeight, word LineHeight, document LineHeight, docx LineHeight" +keywords: "line height, superdoc line height, word line height, document line spacing, docx line height" --- import Description from '/snippets/extensions/line-height.mdx' -## Options - -Configure the extension behavior: - - - Block types to add line height support to - - - - Default configuration - - - - Default unit for line height values - - -## Attributes - -Node attributes that can be set and retrieved: - - - Line height value - - ## Commands ### `setLineHeight` -Set line height for blocks - - -Applies to paragraphs and headings - +Set line height as a multiplier (e.g., 1.5 for 1.5x line spacing). **Example:** ```javascript editor.commands.setLineHeight(1.5) -editor.commands.setLineHeight('24px') editor.commands.setLineHeight(2) ``` **Parameters:** - - Line height to apply + + Line height multiplier (e.g., 1.0 for single, 1.5, 2.0 for double) ### `unsetLineHeight` -Remove line height - - -Reverts to default line spacing - +Remove line height and revert to default line spacing. **Example:** @@ -70,15 +37,9 @@ Reverts to default line spacing editor.commands.unsetLineHeight() ``` -## Types - -### `LineHeightValue` - -Line height as number (1.5) or string with unit ('1.5em', '24px') - -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' - + diff --git a/apps/docs/extensions/link.mdx b/apps/docs/extensions/link.mdx index dd6273c931..bbc360ceef 100644 --- a/apps/docs/extensions/link.mdx +++ b/apps/docs/extensions/link.mdx @@ -153,7 +153,7 @@ Link options for setLink command -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/linked-styles.mdx b/apps/docs/extensions/linked-styles.mdx index 66b1da1336..151542acbf 100644 --- a/apps/docs/extensions/linked-styles.mdx +++ b/apps/docs/extensions/linked-styles.mdx @@ -1,39 +1,18 @@ --- -title: CustomSelection extension -sidebarTitle: "Custom Selection" -keywords: "CustomSelection extension, superdoc CustomSelection, word CustomSelection, document CustomSelection, docx CustomSelection" +title: Linked Styles extension +sidebarTitle: "Linked Styles" +keywords: "linked styles, superdoc linked styles, word styles, document styles, docx styles" --- -import Description from '/snippets/extensions/custom-selection.mdx' +import Description from '/snippets/extensions/linked-styles.mdx' ## Commands -### `restorePreservedSelection` - -Restore the preserved selection - - -Used internally to maintain selection when interacting with toolbar - - -**Example:** - -```javascript -// Restore selection after toolbar interaction -editor.commands.restorePreservedSelection() -``` - -**Returns:** `Function` Command function - ### `setLinkedStyle` -Apply a linked style to the selected paragraphs - - -Works with custom selection preservation - +Apply a linked style to the selected paragraphs. **Example:** @@ -50,17 +29,14 @@ editor.commands.setLinkedStyle(style); ### `toggleLinkedStyle` -Toggle a linked style on the current selection - - -Removes style if already applied, applies it if not - +Toggle a linked style on the current selection. Removes the style if already applied, applies it if not. **Example:** ```javascript const style = editor.helpers.linkedStyles.getStyleById('Heading1'); editor.commands.toggleLinkedStyle(style) +editor.commands.toggleLinkedStyle(style, 'paragraph') ``` **Parameters:** @@ -68,14 +44,13 @@ editor.commands.toggleLinkedStyle(style) The linked style to apply (with id property) + + Node type to restrict toggle to (e.g., 'paragraph') + ### `setStyleById` -Apply a linked style by its ID - - -Looks up the style from loaded Word styles - +Apply a linked style by its ID. **Example:** @@ -94,13 +69,12 @@ editor.commands.setStyleById('Normal') ### `getStyles` -Get all available linked styles +Get all available linked styles from the document. **Example:** ```javascript const styles = editor.helpers.linkedStyles.getStyles(); -// Returns all styles from the Word document ``` **Returns:** @@ -111,7 +85,7 @@ const styles = editor.helpers.linkedStyles.getStyles(); ### `getStyleById` -Get a specific style by ID +Get a specific style by ID. **Example:** @@ -133,45 +107,9 @@ const headingStyle = editor.helpers.linkedStyles.getStyleById('Heading1'); ## Types -### `SelectionState` - -Selection state - - - - Whether editor is focused - - - Stored selection - - - Whether to show selection decoration - - - Whether to skip clearing selection on next focus - - - -### `ParentNodeInfo` - - - - The position of the parent node. - - - The start position of the parent node. - - - The depth of the parent node. - - - The parent node. - - - ### `LinkedStyle` -Style definition from Word document +Style definition from a Word document. @@ -186,8 +124,8 @@ Style definition from Word document -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' - + diff --git a/apps/docs/extensions/list-item.mdx b/apps/docs/extensions/list-item.mdx index 165dd1e5ad..d14eccb64a 100644 --- a/apps/docs/extensions/list-item.mdx +++ b/apps/docs/extensions/list-item.mdx @@ -1,295 +1,37 @@ --- -title: ListItem extension +title: List item sidebarTitle: "List Item" -keywords: "ListItem extension, superdoc ListItem, word ListItem, document ListItem, docx ListItem" +keywords: "list item, superdoc list item, word list item, document list item, docx list item" --- import Description from '/snippets/extensions/list-item.mdx' -## Options + +List item behavior is handled by the [Paragraph extension](/extensions/paragraph). Lists in SuperDoc are paragraphs with numbering properties, matching how Word stores lists internally. + -Configure the extension behavior: - - - HTML attributes for list item elements - - - - Name of bullet list node type - - - - Name of ordered list node type - - -## Attributes - -Node attributes that can be set and retrieved: - - - Virtual attribute for marker display - - - - Level text template for numbering - - - - Numbering format type - - - - List level hierarchy - - - - Level justification (left, right, center) - - - - Indentation and spacing info - - - - Run properties for list item - - - - Numbering definition ID - - - - Numbering properties type - - - - Current nesting level - - - - Additional attributes - - - - Spacing configuration - - - - Indentation settings - - - - Marker styling - - - - Linked style ID - - - - Custom numbering format - - - - Font family from import - - - - Font size from import - - -## Commands - -### `setLinkedStyle` - -Apply a linked style to the selected paragraphs - - -Works with custom selection preservation - - -**Example:** - -```javascript -const style = editor.helpers.linkedStyles.getStyleById('Heading1'); -editor.commands.setLinkedStyle(style); -``` - -**Parameters:** - - - The style object to apply - - -### `toggleLinkedStyle` - -Toggle a linked style on the current selection - - -Removes style if already applied, applies it if not - - -**Example:** - -```javascript -const style = editor.helpers.linkedStyles.getStyleById('Heading1'); -editor.commands.toggleLinkedStyle(style) -editor.commands.toggleLinkedStyle(style, 'paragraph') -``` - -**Parameters:** - - - The linked style to apply (with id property) - - - Node type to restrict toggle to (e.g., 'paragraph') - - -### `setStyleById` - -Apply a linked style by its ID - - -Looks up the style from loaded Word styles - - -**Example:** - -```javascript -editor.commands.setStyleById('Heading1') -editor.commands.setStyleById('Normal') -``` - -**Parameters:** - - - The style ID to apply (e.g., 'Heading1') - - -### `restorePreservedSelection` - -Restore the preserved selection - - -Used internally to maintain selection when interacting with toolbar - - -**Example:** - -```javascript -// Restore selection after toolbar interaction -editor.commands.restorePreservedSelection() -``` - -**Returns:** `Function` Command function - -## Helpers - -### `getStyles` - -Get all available linked styles - -**Example:** - -```javascript -const styles = editor.helpers.linkedStyles.getStyles(); -// Returns all styles from the Word document -``` - -**Returns:** - - - Array of linked style objects - - -### `getStyleById` - -Get a specific style by ID - -**Example:** - -```javascript -const headingStyle = editor.helpers.linkedStyles.getStyleById('Heading1'); -``` - -**Parameters:** - - - The style ID to find - - -**Returns:** - - - The style object or undefined - - -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| -| splitListItem() | `Enter` | Split list item at cursor | -| createParagraphNear() | `Shift-Enter` | Create paragraph in list | -| increaseListIndent() | `Tab` | Increase list indentation | -| decreaseListIndent() | `Shift-Tab` | Decrease list indentation | - -## Types - -### `IndentObject` - - - - The left indent value - - - The right indent value - - - The first line indent value - - - The hanging indent value - - - -### `LinkedStyle` - -Style definition from Word document - - - - Style ID (e.g., 'Heading1', 'Normal') - - - Style type ('paragraph' or 'character') - - - Style definition from Word - - - -### `SelectionState` - -Selection state +| (split item) | `Enter` | Split list item at cursor | +| (line break) | `Shift-Enter` | Add a line break within the current item | +| (indent) | `Tab` | Increase nesting level | +| (outdent) | `Shift-Tab` | Decrease nesting level | - - - Whether editor is focused - - - Stored selection - - - Whether to show selection decoration - - +## Numbering formats +Supported numbering formats from Word: +- **Decimal** — 1, 2, 3, 4... +- **Lower alpha** — a, b, c, d... +- **Upper alpha** — A, B, C, D... +- **Lower roman** — i, ii, iii, iv... +- **Upper roman** — I, II, III, IV... -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' - + diff --git a/apps/docs/extensions/mention.mdx b/apps/docs/extensions/mention.mdx index baedc18f8a..ce381c511c 100644 --- a/apps/docs/extensions/mention.mdx +++ b/apps/docs/extensions/mention.mdx @@ -29,7 +29,7 @@ Node attributes that can be set and retrieved: -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/noderesizer.mdx b/apps/docs/extensions/noderesizer.mdx index aeb1cca115..f72148b68b 100644 --- a/apps/docs/extensions/noderesizer.mdx +++ b/apps/docs/extensions/noderesizer.mdx @@ -9,7 +9,7 @@ import Description from '/snippets/extensions/node-resizer.mdx' -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/ordered-list.mdx b/apps/docs/extensions/ordered-list.mdx index 6d9d635564..5ec2fcb761 100644 --- a/apps/docs/extensions/ordered-list.mdx +++ b/apps/docs/extensions/ordered-list.mdx @@ -1,74 +1,22 @@ --- -title: OrderedList extension +title: Ordered list sidebarTitle: "Ordered List" -keywords: "OrderedList extension, superdoc OrderedList, word OrderedList, document OrderedList, docx OrderedList" +keywords: "ordered list, superdoc ordered list, word ordered list, document numbered list, docx ordered list" --- import Description from '/snippets/extensions/ordered-list.mdx' -## Options - -Configure the extension behavior: - - - Name of list item node type - - - - HTML attributes for ordered list elements - - - - Whether to preserve marks when creating lists - - - - Whether to preserve attributes - - - - Available list style types - - -## Attributes - -Node attributes that can be set and retrieved: - - - Starting number for the list - - - - Block identifier for tracking - - - - Synchronization identifier - - - - List identifier - - - - List style type (decimal, lowerAlpha, lowerRoman) - - - - Additional attributes - + +Ordered list functionality is part of the [Paragraph extension](/extensions/paragraph). There is no separate ordered list extension. + ## Commands ### `toggleOrderedList` -Toggle ordered list formatting - - -Converts selection to ordered list or back to paragraphs - +Toggle ordered list formatting on the current selection. Converts selected paragraphs to numbered list items or removes list formatting. **Example:** @@ -76,52 +24,30 @@ Converts selection to ordered list or back to paragraphs editor.commands.toggleOrderedList() ``` -### `restartListNodes` - -Restart list node numbering +### `restartNumbering` - -Resets list numbering for specified nodes - +Restart list numbering from the current position. **Example:** ```javascript -editor.commands.restartListNodes(nodes, position) +editor.commands.restartNumbering() ``` -**Parameters:** - - - Nodes to restart - - - Starting position - - -### `updateOrderedListStyleType` - -Update ordered list style type based on nesting level - - -Cycles through decimal -> lowerAlpha -> lowerRoman based on depth - - -**Example:** - -```javascript -editor.commands.updateOrderedListStyleType() -``` - -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| | toggleOrderedList() | `⌘/Ctrl-Shift-7` | Toggle ordered list | +| (indent) | `Tab` | Increase list indentation | +| (outdent) | `Shift-Tab` | Decrease list indentation | + +## Input rules +Type `1. ` followed by a space to start a numbered list automatically. -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' - + diff --git a/apps/docs/extensions/page-number.mdx b/apps/docs/extensions/page-number.mdx index 8ce942dd30..8848702b20 100644 --- a/apps/docs/extensions/page-number.mdx +++ b/apps/docs/extensions/page-number.mdx @@ -50,14 +50,15 @@ editor.commands.addTotalPageCount() **Returns:** `Function` Command function -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| -| addAutoPageNumber() | `⌘/Ctrl-Shift-alt-p` | Insert page number | +| addAutoPageNumber() | `⌘/Ctrl-Shift-Alt-p` | Insert page number | +| addTotalPageCount() | `⌘/Ctrl-Shift-Alt-c` | Insert total page count | -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/paragraph.mdx b/apps/docs/extensions/paragraph.mdx index c218faf9eb..6abee0474c 100644 --- a/apps/docs/extensions/paragraph.mdx +++ b/apps/docs/extensions/paragraph.mdx @@ -8,60 +8,51 @@ import Description from '/snippets/extensions/paragraph.mdx' -## Options +## Commands -Configure the extension behavior: +### `toggleBulletList` - - Supported heading levels - +Convert selected paragraphs to a bullet list, or remove list formatting if already a bullet list. - - HTML attributes for paragraph elements - +```javascript +editor.commands.toggleBulletList() +``` -## Attributes +### `toggleOrderedList` -Node attributes that can be set and retrieved: +Convert selected paragraphs to an ordered list, or remove list formatting if already an ordered list. - - Paragraph spacing configuration - +```javascript +editor.commands.toggleOrderedList() +``` - - Additional HTML attributes - +### `restartNumbering` - - Text formatting marks - +Reset list numbering for the current list item and following items. - - Indentation settings - +```javascript +editor.commands.restartNumbering() +``` - - Paragraph borders - +## Keyboard shortcuts - - CSS class name - +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleOrderedList() | `Mod-Shift-7` | Toggle ordered list | +| toggleBulletList() | `Mod-Shift-8` | Toggle bullet list | +| (split paragraph) | `Enter` | Split paragraph at cursor | +| (line break) | `Shift-Enter` | Insert line break without list properties | +| (indent) | `Tab` | Increase list indent level | +| (outdent) | `Shift-Tab` | Decrease list indent level | - - Linked style identifier - +## Input rules - - Text justification - +| Trigger | Result | +|---------|--------| +| `- `, `+ `, or `* ` at line start | Create bullet list | +| `1. ` (or any number) at line start | Create ordered list | - - Tab stop positions - - - -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/permission-ranges.mdx b/apps/docs/extensions/permission-ranges.mdx new file mode 100644 index 0000000000..aa3387042e --- /dev/null +++ b/apps/docs/extensions/permission-ranges.mdx @@ -0,0 +1,54 @@ +--- +title: Permission Ranges extension +sidebarTitle: "Permission Ranges" +keywords: "Permission Ranges extension, superdoc Permission Ranges, word Permission Ranges, document protection, docx permission" +--- + +import Description from '/snippets/extensions/permission-ranges.mdx' + + + +## How it works + +Permission ranges define editable regions within a protected Word document. The extension: + +1. Parses `permStart` and `permEnd` markers from the document +2. Matches the current user's email against the `ed` (specific editor) or `edGrp` (editor group) attributes +3. Allows edits only within matched permission ranges +4. Blocks edits outside permitted regions + +When a document is in viewing mode and has permission ranges matching the current user, the extension automatically enables editing within those ranges. + +## Permission matching + +Ranges can target specific users or groups: + +```xml + + + + + + + +``` + +The `ed` attribute uses the format `domain\username`, matched against the user email configured in SuperDoc. + +## Word export + +Permission ranges export as native Word permission markers: + +```xml + + + Editable content here + + +``` + +## Source code + +import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' + + diff --git a/apps/docs/extensions/placeholder.mdx b/apps/docs/extensions/placeholder.mdx index 75c7fe9bc7..ec1308f4e6 100644 --- a/apps/docs/extensions/placeholder.mdx +++ b/apps/docs/extensions/placeholder.mdx @@ -17,7 +17,7 @@ Configure the extension behavior: -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/popover-plugin.mdx b/apps/docs/extensions/popover-plugin.mdx index 522ed898fb..5906a3f2c7 100644 --- a/apps/docs/extensions/popover-plugin.mdx +++ b/apps/docs/extensions/popover-plugin.mdx @@ -9,7 +9,7 @@ import Description from '/snippets/extensions/popover-plugin.mdx' -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/run-item.mdx b/apps/docs/extensions/run-item.mdx index 35b090bc30..3ba53f3daf 100644 --- a/apps/docs/extensions/run-item.mdx +++ b/apps/docs/extensions/run-item.mdx @@ -9,8 +9,8 @@ import Description from '/snippets/extensions/run-item.mdx' -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' - + diff --git a/apps/docs/extensions/search.mdx b/apps/docs/extensions/search.mdx index fc33c6c8d9..7e3e96a700 100644 --- a/apps/docs/extensions/search.mdx +++ b/apps/docs/extensions/search.mdx @@ -42,7 +42,16 @@ const regexMatches = editor.commands.search(/test/i) **Parameters:** - Search string or pattern + Search string, regex, or regex shorthand (e.g., `'/pattern/flags'`) + + + Optional settings + + + Apply CSS highlight classes to matches + + + Maximum number of matches to return ### `goToSearchResult` @@ -88,7 +97,7 @@ Search match object -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/shape-container.mdx b/apps/docs/extensions/shape-container.mdx index 6eecaffb57..0fc2931e0c 100644 --- a/apps/docs/extensions/shape-container.mdx +++ b/apps/docs/extensions/shape-container.mdx @@ -29,7 +29,7 @@ Node attributes that can be set and retrieved: -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/shape-textbox.mdx b/apps/docs/extensions/shape-textbox.mdx index 46f3735443..44bdfd5ee4 100644 --- a/apps/docs/extensions/shape-textbox.mdx +++ b/apps/docs/extensions/shape-textbox.mdx @@ -17,7 +17,7 @@ Configure the extension behavior: -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/slash-menu.mdx b/apps/docs/extensions/slash-menu.mdx index d2a5e377d7..699da0a653 100644 --- a/apps/docs/extensions/slash-menu.mdx +++ b/apps/docs/extensions/slash-menu.mdx @@ -9,7 +9,7 @@ import Description from '/snippets/extensions/slash-menu.mdx' -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/strike.mdx b/apps/docs/extensions/strike.mdx index a96e16f10e..e737dc6454 100644 --- a/apps/docs/extensions/strike.mdx +++ b/apps/docs/extensions/strike.mdx @@ -48,14 +48,14 @@ Toggle strikethrough formatting editor.commands.toggleStrike() ``` -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| -| toggleStrike() | `⌘/Ctrl-Shift-s` | Toggle strikethrough formatting | +| toggleStrike() | `⌘/Ctrl-Shift-x` | Toggle strikethrough formatting | -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/structured-content.mdx b/apps/docs/extensions/structured-content.mdx index 75efffe852..244a33d771 100644 --- a/apps/docs/extensions/structured-content.mdx +++ b/apps/docs/extensions/structured-content.mdx @@ -109,6 +109,44 @@ Removes a structured content by ID. Removes a structured content at cursor, preserving its content. +### `updateStructuredContentByGroup` + +Update all structured content fields that share the same group identifier. + +**Example:** + +```javascript +editor.commands.updateStructuredContentByGroup('pricing', { + text: '$99.00' +}) +``` + +**Parameters:** + + + Group identifier to match + + + Update options (same as `updateStructuredContentById`) + + +### `deleteStructuredContentByGroup` + +Remove all structured content fields that share the same group identifier. + +**Example:** + +```javascript +editor.commands.deleteStructuredContentByGroup('pricing') +editor.commands.deleteStructuredContentByGroup(['pricing', 'deprecated']) +``` + +**Parameters:** + + + Group identifier or array of group identifiers + + ### `appendRowsToStructuredContentTable` Append multiple rows to the end of a table inside a structured content block. @@ -191,6 +229,26 @@ console.log(`Block contains ${tables.length} table(s)`); +### `getStructuredContentByGroup` + +Find all structured content nodes that share the same group identifier. + +**Example:** + +```javascript +const fields = editor.helpers.getStructuredContentByGroup('pricing', editor.state); +fields.forEach(({ node, pos }) => { + console.log(node.attrs.tag, pos); +}); +``` + +**Parameters:** + + + Group identifier or array of group identifiers + + + ### `getStructuredContentTags` Get all structured content tags (inline and block) in the document @@ -295,7 +353,7 @@ if (field.length) console.log("Found field:", field[0].node.attrs); -## Source Code +## Source code import { SourceCodeLink } from "/snippets/components/source-code-link.jsx"; diff --git a/apps/docs/extensions/tab.mdx b/apps/docs/extensions/tab.mdx index 5c627839a9..ed32f57d3d 100644 --- a/apps/docs/extensions/tab.mdx +++ b/apps/docs/extensions/tab.mdx @@ -25,7 +25,7 @@ Node attributes that can be set and retrieved: -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/table-cell.mdx b/apps/docs/extensions/table-cell.mdx index ebad8692a4..d8f8d8906d 100644 --- a/apps/docs/extensions/table-cell.mdx +++ b/apps/docs/extensions/table-cell.mdx @@ -115,7 +115,7 @@ Cell background configuration -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/table-header.mdx b/apps/docs/extensions/table-header.mdx index b8f2557f85..08a20de16c 100644 --- a/apps/docs/extensions/table-header.mdx +++ b/apps/docs/extensions/table-header.mdx @@ -33,7 +33,7 @@ Node attributes that can be set and retrieved: -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/table-of-contents.mdx b/apps/docs/extensions/table-of-contents.mdx new file mode 100644 index 0000000000..8d144241b0 --- /dev/null +++ b/apps/docs/extensions/table-of-contents.mdx @@ -0,0 +1,38 @@ +--- +title: Table of Contents extension +sidebarTitle: "Table of Contents" +keywords: "Table of Contents extension, superdoc Table of Contents, word Table of Contents, document Table of Contents, docx Table of Contents, TOC" +--- + +import Description from '/snippets/extensions/table-of-contents.mdx' + + + + +Table of contents blocks are managed automatically during Word document import and export. There are no commands to programmatically create or update a TOC. + + +## Word export + +Tables of contents export as Word structured document tags with field instructions: + +```xml + + + + + + + + TOC \o "1-3" + + + + +``` + +## Source code + +import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' + + diff --git a/apps/docs/extensions/table-row.mdx b/apps/docs/extensions/table-row.mdx index 7b525e8478..d1c85fc77b 100644 --- a/apps/docs/extensions/table-row.mdx +++ b/apps/docs/extensions/table-row.mdx @@ -133,7 +133,7 @@ applied to the last row of the parent object. -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/table.mdx b/apps/docs/extensions/table.mdx index 5fb4a54df8..2194bc6962 100644 --- a/apps/docs/extensions/table.mdx +++ b/apps/docs/extensions/table.mdx @@ -368,6 +368,25 @@ editor.commands.setCellBackground('ff0000') Color value (hex with or without #) +### `appendRowsWithContent` + +Append rows with content to an existing table. + +**Example:** + +```javascript +editor.commands.appendRowsWithContent({ + valueRows: [['Cell A', 'Cell B'], ['Cell C', 'Cell D']], + copyRowStyle: true +}) +``` + +**Parameters:** + + + Object with `tablePos`, `tableNode`, `valueRows` (array of row arrays), and optional `copyRowStyle` boolean + + ### `deleteCellAndTableBorders` Remove all borders from table and its cells @@ -384,14 +403,16 @@ editor.commands.deleteCellAndTableBorders() **Returns:** `Function` Command -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| | goToNextCell/addRowAfter() | `Tab` | Navigate to next cell or add row | | goToPreviousCell() | `Shift-Tab` | Navigate to previous cell | | deleteTableWhenSelected() | `Backspace` | Delete table when all cells selected | +| deleteTableWhenSelected() | `Mod-Backspace` | Delete table when all cells selected | | deleteTableWhenSelected() | `Delete` | Delete table when all cells selected | +| deleteTableWhenSelected() | `Mod-Delete` | Delete table when all cells selected | ## Types @@ -825,7 +846,7 @@ Border creation options -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/text-align.mdx b/apps/docs/extensions/text-align.mdx index 4f36e19ad3..1e50949968 100644 --- a/apps/docs/extensions/text-align.mdx +++ b/apps/docs/extensions/text-align.mdx @@ -12,35 +12,15 @@ import Description from '/snippets/extensions/text-align.mdx' Configure the extension behavior: - - Node types to apply alignment to - - Available alignment options - - Default text alignment - - -## Attributes - -Node attributes that can be set and retrieved: - - - Text alignment value (left, center, right, justify) - - ## Commands ### `setTextAlign` -Set text alignment - - -Applies to all configured node types (heading, paragraph by default) - +Set text alignment on the current paragraph. **Example:** @@ -69,7 +49,7 @@ Resets alignment to the default value editor.commands.unsetTextAlign() ``` -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| @@ -79,7 +59,7 @@ editor.commands.unsetTextAlign() | setTextAlign('justify')() | `⌘/Ctrl-Shift-j` | Justify text | -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/text-indent.mdx b/apps/docs/extensions/text-indent.mdx index 6f45a82139..dde97c2c6b 100644 --- a/apps/docs/extensions/text-indent.mdx +++ b/apps/docs/extensions/text-indent.mdx @@ -1,92 +1,48 @@ --- -title: TextIndent extension +title: Text Indent sidebarTitle: "Text Indent" -keywords: "TextIndent extension, superdoc TextIndent, word TextIndent, document TextIndent, docx TextIndent" +keywords: "text indent, superdoc text indent, word text indent, document indentation, docx indent" --- import Description from '/snippets/extensions/text-indent.mdx' -## Options - -Configure the extension behavior: - - - Node types to apply indentation to - - - - Default indentation settings - - - - Default unit for indentation (in, cm, px, etc.) - - - - Default increment/decrement value - - -## Attributes - -Node attributes that can be set and retrieved: - - - Text indentation value with unit (e.g., '0.5in') - - ## Commands -### `setTextIndent` +### `setTextIndentation` -Set text indentation - - -Accepts any valid CSS unit (in, cm, px, em, etc.) - +Set text indentation in points. **Example:** ```javascript -// Set to 0.5 inches -setTextIndent('0.5in') +// Set to 72 points (1 inch) +editor.commands.setTextIndentation(72) -// Set to 2 centimeters -setTextIndent('2cm') +// Set to 36 points (0.5 inch) +editor.commands.setTextIndentation(36) ``` **Parameters:** - - Indentation value with unit (e.g., '0.5in', '2cm') + + Indentation value in points -**Returns:** `Function` Command function - -### `unsetTextIndent` - -Remove text indentation +### `unsetTextIndentation` - -Removes all indentation from the selected nodes - +Remove text indentation from selected paragraphs. **Example:** ```javascript -editor.commands.unsetTextIndent() +editor.commands.unsetTextIndentation() ``` -**Returns:** `Function` Command function - ### `increaseTextIndent` -Increase text indentation - - -Creates initial indent if none exists - +Increase text indentation by 36 points (0.5 inch). **Example:** @@ -94,15 +50,9 @@ Creates initial indent if none exists editor.commands.increaseTextIndent() ``` -**Returns:** `Function` Command function - ### `decreaseTextIndent` -Decrease text indentation - - -Removes indentation completely if it reaches 0 or below - +Decrease text indentation by 36 points. Removes indentation completely if it reaches 0 or below. **Example:** @@ -110,11 +60,9 @@ Removes indentation completely if it reaches 0 or below editor.commands.decreaseTextIndent() ``` -**Returns:** `Function` Command function - -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' - + diff --git a/apps/docs/extensions/text-style.mdx b/apps/docs/extensions/text-style.mdx index f5c93d23c5..8517fadc42 100644 --- a/apps/docs/extensions/text-style.mdx +++ b/apps/docs/extensions/text-style.mdx @@ -18,10 +18,14 @@ Configure the extension behavior: ## Attributes -Node attributes that can be set and retrieved: +Mark attributes that can be set and retrieved: - - Style identifier for referencing predefined styles + + Vertical alignment for superscript and subscript. Values: `'superscript'`, `'subscript'`, `'baseline'` + + + + Custom vertical position offset in points (e.g., `'2pt'`, `'-1.5pt'`). Takes precedence over `vertAlign` when both are present. ## Commands @@ -40,27 +44,7 @@ Automatically checks if any style attributes exist before removal editor.commands.removeEmptyTextStyle() ``` -## Types - -### `ParentNodeInfo` - - - - The position of the parent node. - - - The start position of the parent node. - - - The depth of the parent node. - - - The parent node. - - - - -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/text-transform.mdx b/apps/docs/extensions/text-transform.mdx index 95bf25cf8c..54e00711fe 100644 --- a/apps/docs/extensions/text-transform.mdx +++ b/apps/docs/extensions/text-transform.mdx @@ -25,7 +25,7 @@ Node attributes that can be set and retrieved: -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/extensions/track-changes.mdx b/apps/docs/extensions/track-changes.mdx index ea610473d1..2e31920171 100644 --- a/apps/docs/extensions/track-changes.mdx +++ b/apps/docs/extensions/track-changes.mdx @@ -1,79 +1,143 @@ --- -title: Track Changes Extension +title: Track Changes extension sidebarTitle: Track Changes --- -Track Changes records all edits with author attribution and timestamps, exactly like Microsoft Word. +Track Changes records all edits with author attribution and timestamps, matching Microsoft Word's revision tracking. ## Usage Enable through document mode: ```javascript -// Start tracking -superdoc.setDocumentMode('suggesting'); +superdoc.setDocumentMode('suggesting'); // Enable tracking +superdoc.setDocumentMode('editing'); // Disable tracking +``` + +Or toggle programmatically: + +```javascript +editor.commands.enableTrackChanges() +editor.commands.disableTrackChanges() +editor.commands.toggleTrackChanges() ``` ## Commands +### Accept changes + ```javascript -// Switch modes (controls tracking) -superdoc.setDocumentMode('suggesting'); // Enable tracking -superdoc.setDocumentMode('editing'); // Disable tracking +// Accept at current selection +editor.commands.acceptTrackedChangeBySelection() -// Review changes -editor.commands.acceptChange(); -editor.commands.rejectChange(); -editor.commands.acceptAllChanges(); -editor.commands.rejectAllChanges(); +// Accept a specific change by ID +editor.commands.acceptTrackedChangeById('change-123') -// Navigate -editor.commands.goToNextChange(); -editor.commands.goToPreviousChange(); +// Accept a change object (with start/end positions) +editor.commands.acceptTrackedChange({ trackedChange: { start: 10, end: 50 } }) -// View modes -editor.commands.toggleTrackChangesShowOriginal(); -editor.commands.toggleTrackChangesShowFinal(); +// Accept changes in a range +editor.commands.acceptTrackedChangesBetween(10, 50) + +// Accept all changes in the document +editor.commands.acceptAllTrackedChanges() + +// Toolbar-aware accept (uses active thread or selection) +editor.commands.acceptTrackedChangeFromToolbar() ``` -## Working with changes +### Reject changes ```javascript -import { trackChangesHelpers } from '@harbour-enterprises/superdoc'; +// Reject at current selection +editor.commands.rejectTrackedChangeOnSelection() + +// Reject a specific change by ID +editor.commands.rejectTrackedChangeById('change-123') + +// Reject a change object +editor.commands.rejectTrackedChange({ trackedChange: { start: 10, end: 50 } }) -// Get all changes -const changes = trackChangesHelpers.getAllChanges(editor.state); +// Reject changes in a range +editor.commands.rejectTrackedChangesBetween(10, 50) -// Filter by user -const userChanges = trackChangesHelpers.getChangesByUser( - editor.state, - 'john@company.com' -); +// Reject all changes in the document +editor.commands.rejectAllTrackedChanges() -// Check state -const isTracking = trackChangesHelpers.isTrackingEnabled(editor.state); +// Toolbar-aware reject +editor.commands.rejectTrackedChangeFromToolbar() +``` + +### Insert tracked change programmatically + +Use `insertTrackedChange` to add tracked edits from external sources (e.g., AI suggestions): + +```javascript +editor.commands.insertTrackedChange({ + from: 10, + to: 25, + text: 'replacement text', + comment: 'AI suggestion: improved wording' +}) +``` + +**Parameters:** + + + Object with `from`, `to`, `text`, `user`, `comment`, `addToHistory`, `emitCommentEvent` + + +### View modes + +```javascript +// Show document as it was before changes +editor.commands.toggleTrackChangesShowOriginal() +editor.commands.enableTrackChangesShowOriginal() +editor.commands.disableTrackChangesShowOriginal() + +// Show document as if all changes were accepted +editor.commands.toggleTrackChangesShowFinal() +editor.commands.enableTrackChangesShowFinal() +``` + +## Helpers + +```javascript +import { trackChangesHelpers } from 'superdoc'; + +// Get all tracked changes in the document +const changes = trackChangesHelpers.getTrackChanges(editor.state); +// Returns: [{ mark, from, to }, ...] + +// Get a specific change by ID +const change = trackChangesHelpers.getTrackChanges(editor.state, 'change-123'); ``` ## Change types -- **Insertions** - Green underline -- **Deletions** - Red strikethrough -- **Format changes** - Yellow highlight +| Type | Mark | Visual | +|------|------|--------| +| Insertion | `trackInsert` | Green underline | +| Deletion | `trackDelete` | Red strikethrough | +| Format change | `trackFormat` | Records before/after formatting | -Each change includes: -- User information -- Timestamp -- Unique ID +Each change includes author name, email, timestamp, and a unique ID. ## Export behavior Changes export to DOCX as Word revisions: ```javascript -// With changes +// Export with changes preserved await superdoc.export(); -// Accept all first -editor.commands.acceptAllChanges(); +// Accept all first, then export clean +editor.commands.acceptAllTrackedChanges(); await superdoc.export(); ``` + +## Source code + +import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' + + diff --git a/apps/docs/extensions/underline.mdx b/apps/docs/extensions/underline.mdx index 48ed29cd39..7481b82205 100644 --- a/apps/docs/extensions/underline.mdx +++ b/apps/docs/extensions/underline.mdx @@ -18,12 +18,16 @@ Configure the extension behavior: ## Attributes -Node attributes that can be set and retrieved: +Mark attributes that can be set and retrieved: Style of underline + + Color of the underline (hex color value) + + ## Commands ### `setUnderline` @@ -62,7 +66,7 @@ editor.commands.toggleUnderline() **Returns:** `Function` Command -## Keyboard Shortcuts +## Keyboard shortcuts | Command | Shortcut | Description | |---------|----------|-------------| @@ -82,7 +86,7 @@ Underline style configuration -## Source Code +## Source code import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' diff --git a/apps/docs/getting-started/ai-agents.mdx b/apps/docs/getting-started/ai-agents.mdx index 0a92ec85b9..ccc0fa9c5d 100644 --- a/apps/docs/getting-started/ai-agents.mdx +++ b/apps/docs/getting-started/ai-agents.mdx @@ -1,85 +1,81 @@ --- title: AI Agents & LLMs sidebarTitle: AI Agents ✨ -keywords: "ai document editing, llm docx, chatgpt word documents, cursor integration, document automation ai, programmatic word editing" +keywords: "ai document editing, llm docx, headless editor, document automation ai, programmatic word editing" --- - -**Looking for programmatic document access?** The [Document API](/document-api/overview) is coming soon with a stable, engine-agnostic interface for querying and manipulating documents. - +SuperDoc can run headless in Node.js for server-side document processing, AI agent workflows, and batch automation. -SuperDoc works seamlessly with AI tools. From Cursor to ChatGPT to your own LLMs. - -## Programmatic Control - -Everything in the UI is available via code: - -- **Fine-grained manipulation** via commands -- **Headless mode** - Run in Node.js -- **Document modes** - Track changes automatically +## Quick example ```javascript -// Headless document generation (Node/SSR-safe) -import { JSDOM } from 'jsdom'; -import { Editor } from '@harbour-enterprises/super-editor'; - -const { window } = new JSDOM(''); -const { document } = window; - -const editor = new Editor({ - fileSource: docxBuffer, // or initialize with options.html/markdown/json - documentId: 'doc-1', - options: { - isHeadless: true, - mockDocument: document, - mockWindow: window, - documentMode: 'suggesting', - } +import { Editor } from 'superdoc/super-editor'; +import OpenAI from 'openai'; + +const openai = new OpenAI(); +const completion = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [{ role: 'user', content: 'Write a service agreement in HTML.' }], }); -editor.commands.insertContent(aiContent, { contentType: 'html' }); +const editor = await Editor.open(templateDocx); +editor.commands.insertContent(completion.choices[0].message.content, { + contentType: 'html', +}); +const docx = await editor.exportDocx(); ``` -[See complete example →](https://github.com/Harbour-Enterprises/SuperDoc/tree/develop/examples/agentic-slack-redlining-example) -## The AI Document Workflow +## Content formats -Your AI generates content. Your users need Word documents. SuperDoc bridges the gap. - -### Simple Integration ```javascript -// AI generates content in any format -const content = await ai.generate("Create a service agreement"); - -// SuperDoc handles it -editor.commands.insertContent(content, { - contentType: 'html' // or 'markdown', 'text', 'schema' -}); - -// Export as real Word document -const docx = await editor.exportDocx(); +editor.commands.insertContent(value, { contentType: 'html' }); // Recommended for LLMs +editor.commands.insertContent(value, { contentType: 'markdown' }); +editor.commands.insertContent(value, { contentType: 'text' }); +editor.commands.insertContent(value, { contentType: 'schema' }); // ProseMirror JSON ``` -### Three Ways to Work +See [Import/Export](/getting-started/import-export) for format details, limitations, and guidance on choosing a format. -**1. Import AI Content** - HTML, Markdown, or plain text from any LLM -**2. Structured Documents** - JSON schema for precise control -**3. Programmatic Commands** - Full automation with headless mode +## AI redlining with track changes -[See detailed import options →](/getting-started/import-export#ai-integration-pattern) +Use `suggesting` mode so AI edits appear as tracked changes that users can accept or reject: -## Quick access for AI assistants +```javascript +const contract = await readFile('./contract.docx'); +const editor = await Editor.open(contract, { + documentMode: 'suggesting', +}); -Working with Cursor, Claude, or ChatGPT? Give your assistant our docs: +// AI suggestions are tracked — users review them in Word +editor.commands.insertContent(aiRevisions, { contentType: 'html' }); +const redlined = await editor.exportDocx(); +``` -```javascript -// Quick reference -'https://docs.superdoc.dev/llms.txt' +## LLM quick reference -// Complete documentation -'https://docs.superdoc.dev/llms-full.txt' +Point your AI assistant at these URLs for SuperDoc context: -// MCP server -'https://docs.superdoc.dev/mcp' +``` +https://docs.superdoc.dev/llms.txt // Quick reference +https://docs.superdoc.dev/llms-full.txt // Complete documentation ``` -Drop these URLs into your AI's context. Now it knows SuperDoc. \ No newline at end of file +## Next steps + + + + Headless mode, Editor.open(), and programmatic control + + + + Content formats, export options, and round-trip behavior + + diff --git a/apps/docs/getting-started/configuration.mdx b/apps/docs/getting-started/configuration.mdx deleted file mode 100644 index 52366ef8a4..0000000000 --- a/apps/docs/getting-started/configuration.mdx +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: Configuration -keywords: "superdoc config, document editor setup, word editor options, docx api configuration, document modes, editor roles" ---- - -SuperDoc needs just two things to work: - -```javascript -new SuperDoc({ - selector: '#editor', // Where to render - document: 'contract.docx' // What to load -}) -``` - -## Common configurations - -### Basic editing - -```javascript -new SuperDoc({ - selector: '#editor', - document: 'contract.docx', - toolbar: '#toolbar', - user: { - name: 'John Smith', - email: 'john@company.com' - } -}) -``` - -### Collaboration setup - -```javascript -new SuperDoc({ - selector: '#editor', - document: 'proposal.docx', - user: { - name: 'Jane Doe', - email: 'jane@company.com' - }, - modules: { - collaboration: { - url: 'wss://server.com' - }, - comments: { - allowResolve: true - } - } -}) -``` - -### Review workflow - -```javascript -new SuperDoc({ - selector: '#editor', - document: 'contract.docx', - documentMode: 'suggesting', // Track all changes - modules: { - comments: { allowResolve: false }, - toolbar: { - groups: { - center: ['acceptChange', 'rejectChange'] - } - } - } -}) -``` - -### Read-only viewer - -```javascript -new SuperDoc({ - selector: '#viewer', - document: 'report.docx', - documentMode: 'viewing', - role: 'viewer', - toolbar: false -}) -``` - -### Read-only viewer with comments - -```javascript -new SuperDoc({ - selector: '#viewer', - document: 'report.docx', - documentMode: 'viewing', - role: 'viewer', - comments: { visible: true }, - trackChanges: { visible: false } -}) -``` - -## Configuration concepts - -### Document modes vs roles - -**Role** = what user can do (permanent) -**Mode** = current editing state (changeable) - -```javascript -role: 'editor' // User CAN edit -documentMode: 'viewing' // Currently NOT editing - -// Role always wins: -role: 'viewer' // User CANNOT edit -documentMode: 'editing' // Ignored - still view-only -``` - -### Loading documents - -```javascript -// From URL -document: '/api/docs/123.docx' - -// From file upload -document: fileInput.files[0] - -// From blob (requires conversion) -const blob = await fetch('/api/doc').then(r => r.blob()) -const file = new File([blob], 'document.docx', { type: blob.type }) -document: file - -// With metadata -document: { - id: 'doc-123', - type: 'docx', - data: fileObject // File or Blob -} -``` - -### Modules - -Modules add features. Enable only what you need: - -```javascript -modules: { - collaboration: { /* settings */ }, // Real-time editing - comments: { /* settings */ }, // Discussions - toolbar: { /* settings */ } // UI controls -} -``` - - -Track Changes is controlled by `documentMode` (set to `'suggesting'`). In -`viewing` mode, tracked changes and comments are hidden unless you set -`trackChanges.visible` and/or `comments.visible` to `true`. - - -[Learn about modules →](/modules) - -## Full reference - -[Complete configuration API →](/core/superdoc/configuration) diff --git a/apps/docs/getting-started/frameworks/angular.mdx b/apps/docs/getting-started/frameworks/angular.mdx index d0a10fb08e..63b594d195 100644 --- a/apps/docs/getting-started/frameworks/angular.mdx +++ b/apps/docs/getting-started/frameworks/angular.mdx @@ -8,14 +8,14 @@ SuperDoc works with Angular through direct DOM manipulation. ## Installation ```bash -npm install @harbour-enterprises/superdoc +npm install superdoc ``` ## Basic component ```typescript import { Component, ElementRef, ViewChild, OnInit, OnDestroy } from '@angular/core'; -import { SuperDoc } from '@harbour-enterprises/superdoc'; +import { SuperDoc } from 'superdoc'; @Component({ selector: 'app-document-editor', diff --git a/apps/docs/getting-started/frameworks/blazor.mdx b/apps/docs/getting-started/frameworks/blazor.mdx deleted file mode 100644 index 6c00bb210c..0000000000 --- a/apps/docs/getting-started/frameworks/blazor.mdx +++ /dev/null @@ -1,199 +0,0 @@ ---- -title: .NET / Blazor -keywords: "blazor docx editor, blazor word component, superdoc blazor, .net docx editor, c# document editor" ---- - -SuperDoc works with both traditional ASP.NET and Blazor applications. - -## ASP.NET MVC/Razor Pages - -```csharp -// Controllers/DocumentController.cs -public class DocumentController : Controller -{ - private readonly IWebHostEnvironment _env; - - public IActionResult Edit(int id) - { - var model = new DocumentViewModel - { - Id = id, - User = User.Identity.Name, - Email = User.FindFirst(ClaimTypes.Email)?.Value - }; - return View(model); - } - - [HttpGet] - public IActionResult Download(int id) - { - var path = Path.Combine(_env.ContentRootPath, "Documents", $"{id}.docx"); - var bytes = System.IO.File.ReadAllBytes(path); - return File(bytes, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); - } -} -``` - -```html - -@model DocumentViewModel - -
- - -``` - -## Blazor Server - -```csharp -// Pages/DocumentEditor.razor -@page "/document/{DocumentId:int}" -@inject IJSRuntime JS -@inject AuthenticationStateProvider AuthProvider - -
- -@code { - [Parameter] public int DocumentId { get; set; } - - private ElementReference editorElement; - private IJSObjectReference? superdocModule; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - var authState = await AuthProvider.GetAuthenticationStateAsync(); - var user = authState.User; - - superdocModule = await JS.InvokeAsync( - "import", "/_content/YourApp/superdoc-interop.js"); - - await superdocModule.InvokeVoidAsync("initSuperDoc", - editorElement, - $"/api/documents/{DocumentId}", - user.Identity.Name, - user.FindFirst(ClaimTypes.Email)?.Value); - } - } - - public async ValueTask DisposeAsync() - { - if (superdocModule != null) - { - await superdocModule.InvokeVoidAsync("cleanup"); - await superdocModule.DisposeAsync(); - } - } -} -``` - -```javascript -// wwwroot/superdoc-interop.js -let superdoc = null; - -export async function initSuperDoc(element, documentUrl, userName, userEmail) { - const { SuperDoc } = await import('https://cdn.jsdelivr.net/npm/@harbour-enterprises/superdoc/dist/superdoc.es.js'); - - superdoc = new SuperDoc({ - selector: element, - document: documentUrl, - user: { - name: userName, - email: userEmail - } - }); -} - -export function cleanup() { - superdoc = null; -} -``` - -## Blazor WebAssembly - -```csharp -// Pages/Editor.razor -@page "/editor" -@inject HttpClient Http -@inject IJSRuntime JS - -
- -@code { - private ElementReference editorElement; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - // Fetch document as blob - var documentBytes = await Http.GetByteArrayAsync("api/documents/sample.docx"); - - // Pass to JavaScript - await JS.InvokeVoidAsync("initEditorWithBlob", - editorElement, - documentBytes); - } - } -} -``` - -```javascript -// wwwroot/index.html -window.initEditorWithBlob = async (element, byteArray) => { - const { SuperDoc } = await import('https://cdn.jsdelivr.net/npm/@harbour-enterprises/superdoc/dist/superdoc.es.js'); - - const blob = new Blob([byteArray], { - type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' - }); - - // Convert Blob to File - const file = new File([blob], 'document.docx', { type: blob.type }); - - new SuperDoc({ - selector: element, - document: file - }); -}; -``` - -## File upload - -```csharp -// API/DocumentsController.cs -[ApiController] -[Route("api/[controller]")] -public class DocumentsController : ControllerBase -{ - [HttpPost] - public async Task Upload(IFormFile file) - { - if (file?.Length > 0) - { - var fileName = $"{Guid.NewGuid()}.docx"; - var path = Path.Combine("Documents", fileName); - - using (var stream = new FileStream(path, FileMode.Create)) - { - await file.CopyToAsync(stream); - } - - return Ok(new { fileName }); - } - - return BadRequest(); - } -} -``` \ No newline at end of file diff --git a/apps/docs/getting-started/frameworks/nextjs.mdx b/apps/docs/getting-started/frameworks/nextjs.mdx deleted file mode 100644 index 0a244afdc0..0000000000 --- a/apps/docs/getting-started/frameworks/nextjs.mdx +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: Next.js -keywords: "nextjs docx editor, next word editor, superdoc nextjs, ssr document editor, dynamic import docx" ---- - -SuperDoc works with Next.js using dynamic imports to avoid SSR issues. - -## Installation - -```bash -npm install @harbour-enterprises/superdoc -``` - -## Basic component - -```jsx -// components/DocumentEditor.jsx -import { useEffect, useRef } from 'react'; -import dynamic from 'next/dynamic'; - -// Prevent SSR issues -const DocumentEditor = dynamic( - () => Promise.resolve(DocumentEditorComponent), - { ssr: false } -); - -function DocumentEditorComponent({ document }) { - const containerRef = useRef(null); - const superdocRef = useRef(null); - - useEffect(() => { - const initEditor = async () => { - const { SuperDoc } = await import('@harbour-enterprises/superdoc'); - - if (containerRef.current) { - superdocRef.current = new SuperDoc({ - selector: containerRef.current, - document - }); - } - }; - - initEditor(); - - return () => { - superdocRef.current = null; - }; - }, [document]); - - return
; -} - -export default DocumentEditor; -``` - -## App Router (Next.js 13+) - -```jsx -// app/editor/page.jsx -'use client'; - -import dynamic from 'next/dynamic'; - -const DocumentEditor = dynamic( - () => import('@/components/DocumentEditor'), - { - ssr: false, - loading: () =>
Loading editor...
- } -); - -export default function EditorPage() { - return ( -
- -
- ); -} -``` - -## API route for document handling - -```javascript -// pages/api/documents/[id].js (Pages Router) -// app/api/documents/[id]/route.js (App Router) - -export async function GET(request, { params }) { - const docId = params.id; - - // Fetch document from storage - const document = await fetchDocumentFromStorage(docId); - - return new Response(document, { - headers: { - 'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' - } - }); -} -``` - -## With authentication - -```jsx -// components/SecureEditor.jsx -import { useSession } from 'next-auth/react'; -import dynamic from 'next/dynamic'; - -const DocumentEditor = dynamic(() => import('./DocumentEditor'), { ssr: false }); - -export default function SecureEditor() { - const { data: session, status } = useSession(); - - if (status === 'loading') return
Loading...
; - if (!session) return
Please sign in
; - - return ( - - ); -} -``` \ No newline at end of file diff --git a/apps/docs/getting-started/frameworks/nuxt.mdx b/apps/docs/getting-started/frameworks/nuxt.mdx deleted file mode 100644 index 375c6f9970..0000000000 --- a/apps/docs/getting-started/frameworks/nuxt.mdx +++ /dev/null @@ -1,130 +0,0 @@ ---- -title: Nuxt.js -keywords: "nuxt docx editor, nuxt word editor, superdoc nuxt, nuxt3 document editor, vue ssr docx" ---- - -SuperDoc requires client-side rendering in Nuxt due to DOM dependencies. - -## Installation - -```bash -npm install @harbour-enterprises/superdoc -``` - -## Basic component - -```vue - - - - - - -``` - -## Plugin setup (Nuxt 3) - -```javascript -// plugins/superdoc.client.js -export default defineNuxtPlugin(() => { - return { - provide: { - initSuperDoc: async (element, options) => { - const { SuperDoc } = await import('@harbour-enterprises/superdoc'); - return new SuperDoc({ selector: element, ...options }); - } - } - }; -}); - -// Usage in component -const { $initSuperDoc } = useNuxtApp(); - -onMounted(async () => { - superdoc = await $initSuperDoc(editor.value, { - document: props.document - }); -}); -``` - -## API endpoint - -```javascript -// server/api/documents/[id].get.js -import { readFile } from 'fs/promises'; -import { resolve } from 'path'; - -export default defineEventHandler(async (event) => { - const id = getRouterParam(event, 'id'); - const filePath = resolve('storage/documents', `${id}.docx`); - - try { - const file = await readFile(filePath); - setHeader(event, 'Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'); - return file; - } catch { - throw createError({ statusCode: 404, statusMessage: 'Document not found' }); - } -}); -``` - -## With authentication (Nuxt 3) - -```vue - - - -``` \ No newline at end of file diff --git a/apps/docs/getting-started/frameworks/php.mdx b/apps/docs/getting-started/frameworks/php.mdx deleted file mode 100644 index 236b7f8122..0000000000 --- a/apps/docs/getting-started/frameworks/php.mdx +++ /dev/null @@ -1,165 +0,0 @@ ---- -title: PHP -keywords: "php docx editor, php word editor, superdoc php, server side docx, php document editor" ---- - -SuperDoc runs client-side but PHP can handle document storage and serving. - -## Basic HTML template - -```php - - - - - - -
- - - - -``` - -## Serving documents - -```php -// document.php - $documentId]); -} -?> -``` - -## Complete PHP example - -```php - 'Guest', 'email' => 'guest@example.com']; -?> - - - - Document Editor - - - - -
- - - - -``` - -## Laravel integration - -```php -// routes/web.php -Route::get('/editor/{document}', function ($documentId) { - return view('editor', ['documentId' => $documentId]); -})->middleware('auth'); - -// resources/views/editor.blade.php -@extends('layout') - -@section('content') -
- - -@endsection -``` \ No newline at end of file diff --git a/apps/docs/getting-started/frameworks/react.mdx b/apps/docs/getting-started/frameworks/react.mdx index a23c1e324f..91a1895701 100644 --- a/apps/docs/getting-started/frameworks/react.mdx +++ b/apps/docs/getting-started/frameworks/react.mdx @@ -8,15 +8,15 @@ SuperDoc works with React 16.8+ (hooks) and React 18+ (concurrent features). ## Install ```bash -npm install @harbour-enterprises/superdoc +npm install superdoc ``` -## Basic Setup +## Basic setup ```jsx import { useEffect, useRef } from 'react'; -import { SuperDoc } from '@harbour-enterprises/superdoc'; -import '@harbour-enterprises/superdoc/style.css'; +import { SuperDoc } from 'superdoc'; +import 'superdoc/style.css'; function DocEditor({ document }) { const containerRef = useRef(null); @@ -39,14 +39,14 @@ function DocEditor({ document }) { } ``` -## Full Component +## Full component Build a reusable editor with controls: ```jsx import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react'; -import { SuperDoc } from '@harbour-enterprises/superdoc'; -import '@harbour-enterprises/superdoc/style.css'; +import { SuperDoc } from 'superdoc'; +import 'superdoc/style.css'; const DocEditor = forwardRef(({ document, user, onReady }, ref) => { const containerRef = useRef(null); @@ -101,7 +101,7 @@ function App() { } ``` -## File Upload +## File upload ```jsx function FileEditor() { @@ -141,8 +141,8 @@ function FileEditor() { ```tsx import { useEffect, useRef, forwardRef } from 'react'; -import { SuperDoc } from '@harbour-enterprises/superdoc'; -import type { SuperDocConfig } from '@harbour-enterprises/superdoc'; +import { SuperDoc } from 'superdoc'; +import type { SuperDocConfig } from 'superdoc'; interface EditorProps { document: string | File | Blob; @@ -199,7 +199,7 @@ const DocEditor = forwardRef( ); ``` -## SSR Support +## SSR support For Next.js or other SSR frameworks: @@ -228,7 +228,7 @@ function SafeEditor(props) { } ``` -## Custom Hook +## Custom hook ```jsx function useSuperDoc(config) { @@ -261,8 +261,8 @@ function useSuperDoc(config) { } ``` -## Next Steps +## Next steps - [Vue Integration](/getting-started/frameworks/vue) - Vue setup - [API Reference](/core/superdoc/configuration) - Configuration options -- [Examples](https://github.com/Harbour-Enterprises/SuperDoc/tree/main/examples/react-example) - Working examples +- [Examples](https://github.com/superdoc-dev/superdoc/tree/main/examples/react-example) - Working examples diff --git a/apps/docs/getting-started/frameworks/ruby-on-rails.mdx b/apps/docs/getting-started/frameworks/ruby-on-rails.mdx deleted file mode 100644 index f821c35f6c..0000000000 --- a/apps/docs/getting-started/frameworks/ruby-on-rails.mdx +++ /dev/null @@ -1,141 +0,0 @@ ---- -title: Ruby on Rails -keywords: "rails docx editor, ruby word editor, superdoc rails, ruby document editor, rails integration" ---- - -SuperDoc integrates with Rails for document storage and serving. - -## Installation - -Add to your layout: - -```erb - -<%= stylesheet_link_tag "https://cdn.jsdelivr.net/npm/@harbour-enterprises/superdoc/dist/style.css" %> -``` - -## Basic view - -```erb - -
- - -``` - -## Active Storage integration - -```ruby -# app/models/document.rb -class Document < ApplicationRecord - has_one_attached :file - belongs_to :user - - validates :file, content_type: ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'] -end - -# app/controllers/documents_controller.rb -class DocumentsController < ApplicationController - before_action :authenticate_user! - - def show - @document = Document.find(params[:id]) - - respond_to do |format| - format.html - format.docx { redirect_to rails_blob_path(@document.file, disposition: "inline") } - end - end - - def create - @document = current_user.documents.build(document_params) - - if @document.save - redirect_to edit_document_path(@document) - else - render :new - end - end - - private - - def document_params - params.require(:document).permit(:file) - end -end -``` - -## Stimulus controller - -```javascript -// app/javascript/controllers/document_editor_controller.js -import { Controller } from "@hotwired/stimulus" - -export default class extends Controller { - static values = { - url: String, - user: Object - } - - async connect() { - const { SuperDoc } = await import('@harbour-enterprises/superdoc'); - - this.superdoc = new SuperDoc({ - selector: this.element, - document: this.urlValue, - user: this.userValue - }); - } - - disconnect() { - this.superdoc = null; - } - - async export() { - if (this.superdoc) { - await this.superdoc.export(); - } - } -} -``` - -```erb - -
-
- - -``` - -## Upload handling - -```ruby -# config/routes.rb -resources :documents do - member do - post :upload - end -end - -# app/controllers/documents_controller.rb -def upload - @document = Document.find(params[:id]) - @document.file.attach(params[:file]) - - render json: { url: rails_blob_path(@document.file) } -end -``` \ No newline at end of file diff --git a/apps/docs/getting-started/frameworks/svelte.mdx b/apps/docs/getting-started/frameworks/svelte.mdx deleted file mode 100644 index d5891a2881..0000000000 --- a/apps/docs/getting-started/frameworks/svelte.mdx +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Svelte -keywords: "svelte docx editor, svelte word component, superdoc svelte, svelte document editor, svelte integration" ---- - -SuperDoc integrates with Svelte through lifecycle functions. - -## Installation - -```bash -npm install @harbour-enterprises/superdoc -``` - -## Basic component - -```svelte - - - -
- - -``` - -## With props - -```svelte - - -
-``` - -## Store integration - -```javascript -// documentStore.js -import { writable } from 'svelte/store'; - -export const superdocInstance = writable(null); - -// Component.svelte - -``` \ No newline at end of file diff --git a/apps/docs/getting-started/frameworks/vanilla-js.mdx b/apps/docs/getting-started/frameworks/vanilla-js.mdx index b35d836e41..95a194dff9 100644 --- a/apps/docs/getting-started/frameworks/vanilla-js.mdx +++ b/apps/docs/getting-started/frameworks/vanilla-js.mdx @@ -6,7 +6,7 @@ keywords: "vanilla javascript docx, plain js word editor, superdoc vanilla, no f SuperDoc works with plain JavaScript. No framework required. -## Basic Setup +## Basic setup @@ -14,15 +14,15 @@ SuperDoc works with plain JavaScript. No framework required. -
- + ``` -## TypeScript Support +## TypeScript support ```vue ``` -## Next Steps +## Next steps - [React Integration](/getting-started/frameworks/react) - React setup - [API Reference](/core/superdoc/configuration) - Configuration options -- [Examples](https://github.com/Harbour-Enterprises/SuperDoc/tree/main/examples/vue-example) - Working examples \ No newline at end of file +- [Examples](https://github.com/superdoc-dev/superdoc/tree/main/examples/vue-example) - Working examples \ No newline at end of file diff --git a/apps/docs/getting-started/import-export.mdx b/apps/docs/getting-started/import-export.mdx index b0f97a9ddf..41fd84bc28 100644 --- a/apps/docs/getting-started/import-export.mdx +++ b/apps/docs/getting-started/import-export.mdx @@ -1,69 +1,53 @@ --- title: Import/Export sidebarTitle: Import/Export -keywords: "import, export, import types, export types, docx to pdf, markdown to docx" +keywords: "import, export, docx export, html import, markdown import, document formats" --- -SuperDoc handles multiple content formats with different levels of support. **We are a Word editor that accepts other formats as input**, not a universal document converter. +SuperDoc is a Word editor that accepts multiple content formats as input. All content is normalized into Word's document model internally. -## Philosophy +## Supported formats -SuperDoc operates on Microsoft Word's document model. HTML and Markdown are normalized into Word concepts on import. For perfect fidelity, use DOCX or JSON formats. +| Format | Import | Export | Round-Trip | Use Case | +|---|---|---|---|---| +| **DOCX** | Full | Full | Perfect | Word documents | +| **JSON** | Full | Full | Perfect | Programmatic control | +| **HTML** | Structure only | Structure only | Visual only | Web content, AI output | +| **Markdown** | CommonMark | CommonMark | Visual only | Documentation, AI output | +| **Text** | Plain text | Plain text | Perfect | Simple content | -## Supported Formats + +HTML and Markdown imports preserve structure (headings, lists, links, tables) but strip CSS styles. + -| Format | Import Support | Export Support | Round-Trip Fidelity | Primary Use Case | -|----------|------------------|------------------|-------------------|-------------------------------------| -| **DOCX** | Full compatibility | Full compatibility | ✅ Perfect | Word documents, complete fidelity | -| **JSON** | Full support | Full support | ✅ Perfect | Automation, programmatic control | -| **HTML** | Structure only | Structure only | ⚠️ Visual only | AI content, migration from web | -| **Markdown** | CommonMark only | CommonMark only | ⚠️ Visual only | Documentation, AI-generated content | -| **Text** | Plain text only | Plain text only | ✅ Perfect | Simple content | -| **PDF** | Not supported | Via API only | N/A | Final output format | +## Importing content -## When to Use Each Format +### At initialization -### Use DOCX/JSON for: -- Preserving all formatting -- Round-trip editing -- Complex documents -- Production workflows +Pass content when creating the SuperDoc instance. -### Use HTML/Markdown for: -- Basic content import when JSON isn't available -- Migrating from legacy systems -- Simple text with minimal structure -- **NOT** for complex documents or formatting preservation - -## Content Import Methods - -### Method 1: Initialize with Content - -Load content when creating the editor or SuperDoc instance. - -#### SuperDoc Component ```javascript -// DOCX file (perfect fidelity) +// DOCX file — full fidelity new SuperDoc({ selector: '#editor', - document: docxFile + document: docxFile // File, Blob, URL string, or config object }); -// HTML content (structure preserved, styles stripped) +// HTML content — requires a base DOCX for styles new SuperDoc({ selector: '#editor', - document: blankDocx, // Must have styles defined + document: blankDocx, html: '

Title

Content

' }); -// Markdown content (converted to Word structure) +// Markdown content new SuperDoc({ selector: '#editor', document: blankDocx, markdown: '# Title\n\nContent with **formatting**' }); -// JSON schema (full control) +// JSON (ProseMirror schema) new SuperDoc({ selector: '#editor', document: blankDocx, @@ -71,193 +55,150 @@ new SuperDoc({ }); ``` -### Method 2: Insert into Existing Document + + The document to load. Strings are treated as URLs. Files and Blobs are used directly. + -Add content to an already-loaded document using commands. + + HTML content to initialize the editor with. Requires a `document` for styles. + -```javascript -// Insert at current cursor position -editor.commands.insertContent(content, { - contentType: 'html' // or 'markdown', 'text', 'schema' -}); - -// AI content integration example -const aiResponse = await ai.generate("Create a contract"); -editor.commands.insertContent(aiResponse, { - contentType: 'html' // AI output gets converted to Word structure -}); -``` + + Markdown content to initialize the editor with. Requires a `document` for styles. + -## HTML Import/Export Behavior + + ProseMirror JSON to override the document content with. + -### What Gets Preserved +### After initialization -| HTML Element | Import Result | Export Result | Notes | -|-------------|--------------|---------------|-------| -| `

` to `

` | Word heading styles | Same heading level | Requires styles in document | -| `

`, `

` | Normal paragraph | `

` | All become paragraphs | -| ``, `` | Bold mark | `` | Character formatting | -| ``, `` | Italic mark | `` | Character formatting | -| `` | Word hyperlink | `` | Links preserved | -| `