From e497eb251f1880bca549d35ab93f8ca3afb9baf9 Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Fri, 23 Jan 2026 11:43:57 -0300 Subject: [PATCH 1/3] chore: move docs to monorepo --- .github/workflows/docs-validation.yml | 34 + .github/workflows/trigger-docs-update.yml | 27 - apps/docs/.gitignore | 5 + apps/docs/README.md | 147 + apps/docs/ai/ai-actions/configuration.mdx | 376 + apps/docs/ai/ai-actions/hooks.mdx | 283 + apps/docs/ai/ai-actions/methods.mdx | 618 ++ apps/docs/ai/ai-actions/overview.mdx | 181 + apps/docs/ai/ai-builder/overview.mdx | 26 + apps/docs/api-reference/authentication.mdx | 28 + apps/docs/api-reference/introduction.mdx | 73 + apps/docs/api-reference/quickstart.mdx | 32 + apps/docs/core/superdoc/configuration.mdx | 357 + apps/docs/core/superdoc/events.mdx | 328 + apps/docs/core/superdoc/methods.mdx | 334 + apps/docs/core/superdoc/overview.mdx | 45 + apps/docs/core/superdoc/properties.mdx | 273 + apps/docs/core/superdoc/types.mdx | 81 + apps/docs/core/supereditor/configuration.mdx | 366 + apps/docs/core/supereditor/hooks.mdx | 341 + apps/docs/core/supereditor/methods.mdx | 564 ++ apps/docs/core/supereditor/overview.mdx | 87 + apps/docs/docs.json | 405 + apps/docs/extensions/block-node.mdx | 194 + apps/docs/extensions/bold.mdx | 39 + apps/docs/extensions/bullet-list.mdx | 82 + apps/docs/extensions/color.mdx | 75 + apps/docs/extensions/comments.mdx | 81 + apps/docs/extensions/content-block.mdx | 114 + apps/docs/extensions/creating-extensions.mdx | 158 + apps/docs/extensions/custom-selection.mdx | 56 + apps/docs/extensions/document-section.mdx | 295 + apps/docs/extensions/document.mdx | 48 + apps/docs/extensions/dropcursor.mdx | 50 + apps/docs/extensions/field-annotation.mdx | 1093 +++ apps/docs/extensions/font-family.mdx | 75 + apps/docs/extensions/font-size.mdx | 99 + apps/docs/extensions/format-commands.mdx | 95 + apps/docs/extensions/gapcursor.mdx | 16 + apps/docs/extensions/heading.mdx | 86 + apps/docs/extensions/highlight.mdx | 77 + apps/docs/extensions/history.mdx | 66 + apps/docs/extensions/image.mdx | 192 + apps/docs/extensions/italic.mdx | 31 + apps/docs/extensions/line-break.mdx | 46 + apps/docs/extensions/line-height.mdx | 84 + apps/docs/extensions/link.mdx | 160 + apps/docs/extensions/linked-styles.mdx | 193 + apps/docs/extensions/list-item.mdx | 295 + apps/docs/extensions/mention.mdx | 36 + apps/docs/extensions/noderesizer.mdx | 16 + apps/docs/extensions/ordered-list.mdx | 127 + apps/docs/extensions/overview.mdx | 51 + apps/docs/extensions/page-number.mdx | 64 + apps/docs/extensions/paragraph.mdx | 68 + apps/docs/extensions/placeholder.mdx | 24 + apps/docs/extensions/popover-plugin.mdx | 16 + apps/docs/extensions/run-item.mdx | 16 + apps/docs/extensions/search.mdx | 95 + apps/docs/extensions/shape-container.mdx | 36 + apps/docs/extensions/shape-textbox.mdx | 24 + apps/docs/extensions/slash-menu.mdx | 16 + apps/docs/extensions/strike.mdx | 62 + apps/docs/extensions/structured-content.mdx | 302 + apps/docs/extensions/tab.mdx | 32 + apps/docs/extensions/table-cell.mdx | 122 + apps/docs/extensions/table-header.mdx | 40 + apps/docs/extensions/table-row.mdx | 140 + apps/docs/extensions/table.mdx | 832 +++ apps/docs/extensions/text-align.mdx | 86 + apps/docs/extensions/text-indent.mdx | 120 + apps/docs/extensions/text-style.mdx | 67 + apps/docs/extensions/text-transform.mdx | 32 + apps/docs/extensions/track-changes.mdx | 79 + apps/docs/extensions/underline.mdx | 89 + apps/docs/getting-started/ai-agents.mdx | 81 + apps/docs/getting-started/configuration.mdx | 155 + apps/docs/getting-started/fonts.mdx | 7 + .../getting-started/frameworks/angular.mdx | 99 + .../getting-started/frameworks/blazor.mdx | 199 + .../getting-started/frameworks/nextjs.mdx | 126 + apps/docs/getting-started/frameworks/nuxt.mdx | 130 + apps/docs/getting-started/frameworks/php.mdx | 165 + .../docs/getting-started/frameworks/react.mdx | 268 + .../frameworks/ruby-on-rails.mdx | 141 + .../getting-started/frameworks/svelte.mdx | 104 + .../getting-started/frameworks/vanilla-js.mdx | 181 + apps/docs/getting-started/frameworks/vue.mdx | 209 + apps/docs/getting-started/import-export.mdx | 263 + apps/docs/getting-started/installation.mdx | 227 + apps/docs/getting-started/introduction.mdx | 52 + .../docs/guides/breaking-changes-v1.mdx | 5 + apps/docs/guides/general/accessibility.mdx | 133 + apps/docs/guides/general/security.mdx | 69 + apps/docs/guides/general/storage.mdx | 92 + apps/docs/guides/migration/prosemirror.mdx | 65 + .../docs/guides/typescript-migration.mdx | 5 + .../collaboration/cloud/liveblocks.mdx | 256 + .../collaboration/cloud/tiptap-cloud.mdx | 215 + .../modules/collaboration/configuration.mdx | 274 + apps/docs/modules/collaboration/overview.mdx | 151 + .../docs/modules/collaboration/quickstart.mdx | 275 + .../collaboration/self-hosted/hocuspocus.mdx | 302 + .../collaboration/self-hosted/overview.mdx | 188 + .../self-hosted/superdoc-yjs.mdx | 388 + .../collaboration/self-hosted/y-sweet.mdx | 275 + apps/docs/modules/comments.mdx | 671 ++ apps/docs/modules/overview.mdx | 104 + apps/docs/modules/toolbar.mdx | 711 ++ apps/docs/openapi.json | 2006 +++++ apps/docs/package.json | 17 + apps/docs/public/icons/react.svg | 1 + apps/docs/public/icons/vanilla-js.svg | 1 + apps/docs/public/icons/vue.svg | 1 + .../public/images/extensions/dropcursor.svg | 35 + .../public/images/extensions/dropcursor2.svg | 52 + .../public/images/extensions/image-chart.png | Bin 0 -> 1517064 bytes .../public/images/extensions/image-icon.png | Bin 0 -> 984256 bytes .../images/extensions/image-landscape.png | Bin 0 -> 1845604 bytes apps/docs/public/images/favicon.png | Bin 0 -> 31161 bytes apps/docs/public/images/logo-dark.png | Bin 0 -> 160787 bytes apps/docs/public/images/logo-light.png | Bin 0 -> 167904 bytes apps/docs/public/images/og-image.png | Bin 0 -> 561289 bytes apps/docs/public/images/og-image2.png | Bin 0 -> 1456187 bytes apps/docs/public/images/og-image3.png | Bin 0 -> 1940727 bytes .../public/images/template-builder/demo.gif | Bin 0 -> 25489186 bytes apps/docs/public/images/twitter-image.png | Bin 0 -> 624726 bytes apps/docs/resources/guides.mdx | 5 + apps/docs/resources/license.mdx | 17 + apps/docs/scripts/add-keywords.js | 205 + apps/docs/scripts/sync-api-docs.js | 37 + apps/docs/scripts/sync-sdk-docs.js | 557 ++ .../snippets/components/source-code-link.jsx | 15 + .../snippets/components/superdoc-editor.jsx | 119 + apps/docs/snippets/extensions/block-node.mdx | 133 + apps/docs/snippets/extensions/bold.mdx | 56 + apps/docs/snippets/extensions/bookmarks.mdx | 86 + apps/docs/snippets/extensions/bullet-list.mdx | 105 + apps/docs/snippets/extensions/color.mdx | 110 + .../snippets/extensions/content-block.mdx | 102 + .../snippets/extensions/custom-selection.mdx | 60 + .../snippets/extensions/document-section.mdx | 68 + apps/docs/snippets/extensions/document.mdx | 50 + apps/docs/snippets/extensions/dropcursor.mdx | 40 + apps/docs/snippets/extensions/font-family.mdx | 77 + apps/docs/snippets/extensions/font-size.mdx | 85 + .../snippets/extensions/format-commands.mdx | 51 + apps/docs/snippets/extensions/gapcursor.mdx | 56 + apps/docs/snippets/extensions/heading.mdx | 95 + apps/docs/snippets/extensions/highlight.mdx | 81 + apps/docs/snippets/extensions/history.mdx | 45 + apps/docs/snippets/extensions/image.mdx | 79 + apps/docs/snippets/extensions/italic.mdx | 60 + apps/docs/snippets/extensions/line-break.mdx | 46 + apps/docs/snippets/extensions/line-height.mdx | 65 + apps/docs/snippets/extensions/link.mdx | 65 + .../snippets/extensions/linked-styles.mdx | 129 + apps/docs/snippets/extensions/list-item.mdx | 131 + apps/docs/snippets/extensions/mention.mdx | 37 + .../docs/snippets/extensions/node-resizer.mdx | 20 + .../docs/snippets/extensions/ordered-list.mdx | 66 + apps/docs/snippets/extensions/page-number.mdx | 60 + apps/docs/snippets/extensions/paragraph.mdx | 38 + apps/docs/snippets/extensions/placeholder.mdx | 18 + .../snippets/extensions/popover-plugin.mdx | 20 + apps/docs/snippets/extensions/run-item.mdx | 28 + apps/docs/snippets/extensions/search.mdx | 56 + .../snippets/extensions/shape-container.mdx | 40 + .../snippets/extensions/shape-textbox.mdx | 33 + apps/docs/snippets/extensions/slash-menu.mdx | 20 + apps/docs/snippets/extensions/strike.mdx | 60 + .../extensions/structured-content.mdx | 116 + apps/docs/snippets/extensions/tab.mdx | 43 + apps/docs/snippets/extensions/table-cell.mdx | 25 + .../docs/snippets/extensions/table-header.mdx | 26 + apps/docs/snippets/extensions/table-row.mdx | 17 + apps/docs/snippets/extensions/table.mdx | 120 + apps/docs/snippets/extensions/text-align.mdx | 75 + apps/docs/snippets/extensions/text-indent.mdx | 76 + apps/docs/snippets/extensions/text-style.mdx | 78 + .../snippets/extensions/text-transform.mdx | 66 + apps/docs/snippets/extensions/underline.mdx | 60 + apps/docs/solutions/esign/api-reference.mdx | 304 + apps/docs/solutions/esign/backend.mdx | 254 + apps/docs/solutions/esign/configuration.mdx | 349 + apps/docs/solutions/esign/introduction.mdx | 73 + apps/docs/solutions/esign/quickstart.mdx | 147 + apps/docs/solutions/overview.mdx | 42 + .../template-builder/api-reference.mdx | 423 ++ .../template-builder/configuration.mdx | 362 + .../template-builder/introduction.mdx | 87 + .../solutions/template-builder/quickstart.mdx | 167 + apps/docs/style.css | 3 + eslint.config.mjs | 4 +- pnpm-lock.yaml | 6552 ++++++++++++++++- 195 files changed, 32683 insertions(+), 214 deletions(-) create mode 100644 .github/workflows/docs-validation.yml delete mode 100644 .github/workflows/trigger-docs-update.yml create mode 100644 apps/docs/.gitignore create mode 100644 apps/docs/README.md create mode 100644 apps/docs/ai/ai-actions/configuration.mdx create mode 100644 apps/docs/ai/ai-actions/hooks.mdx create mode 100644 apps/docs/ai/ai-actions/methods.mdx create mode 100644 apps/docs/ai/ai-actions/overview.mdx create mode 100644 apps/docs/ai/ai-builder/overview.mdx create mode 100644 apps/docs/api-reference/authentication.mdx create mode 100644 apps/docs/api-reference/introduction.mdx create mode 100644 apps/docs/api-reference/quickstart.mdx create mode 100644 apps/docs/core/superdoc/configuration.mdx create mode 100644 apps/docs/core/superdoc/events.mdx create mode 100644 apps/docs/core/superdoc/methods.mdx create mode 100644 apps/docs/core/superdoc/overview.mdx create mode 100644 apps/docs/core/superdoc/properties.mdx create mode 100644 apps/docs/core/superdoc/types.mdx create mode 100644 apps/docs/core/supereditor/configuration.mdx create mode 100644 apps/docs/core/supereditor/hooks.mdx create mode 100644 apps/docs/core/supereditor/methods.mdx create mode 100644 apps/docs/core/supereditor/overview.mdx create mode 100644 apps/docs/docs.json create mode 100644 apps/docs/extensions/block-node.mdx create mode 100644 apps/docs/extensions/bold.mdx create mode 100644 apps/docs/extensions/bullet-list.mdx create mode 100644 apps/docs/extensions/color.mdx create mode 100644 apps/docs/extensions/comments.mdx create mode 100644 apps/docs/extensions/content-block.mdx create mode 100644 apps/docs/extensions/creating-extensions.mdx create mode 100644 apps/docs/extensions/custom-selection.mdx create mode 100644 apps/docs/extensions/document-section.mdx create mode 100644 apps/docs/extensions/document.mdx create mode 100644 apps/docs/extensions/dropcursor.mdx create mode 100644 apps/docs/extensions/field-annotation.mdx create mode 100644 apps/docs/extensions/font-family.mdx create mode 100644 apps/docs/extensions/font-size.mdx create mode 100644 apps/docs/extensions/format-commands.mdx create mode 100644 apps/docs/extensions/gapcursor.mdx create mode 100644 apps/docs/extensions/heading.mdx create mode 100644 apps/docs/extensions/highlight.mdx create mode 100644 apps/docs/extensions/history.mdx create mode 100644 apps/docs/extensions/image.mdx create mode 100644 apps/docs/extensions/italic.mdx create mode 100644 apps/docs/extensions/line-break.mdx create mode 100644 apps/docs/extensions/line-height.mdx create mode 100644 apps/docs/extensions/link.mdx create mode 100644 apps/docs/extensions/linked-styles.mdx create mode 100644 apps/docs/extensions/list-item.mdx create mode 100644 apps/docs/extensions/mention.mdx create mode 100644 apps/docs/extensions/noderesizer.mdx create mode 100644 apps/docs/extensions/ordered-list.mdx create mode 100644 apps/docs/extensions/overview.mdx create mode 100644 apps/docs/extensions/page-number.mdx create mode 100644 apps/docs/extensions/paragraph.mdx create mode 100644 apps/docs/extensions/placeholder.mdx create mode 100644 apps/docs/extensions/popover-plugin.mdx create mode 100644 apps/docs/extensions/run-item.mdx create mode 100644 apps/docs/extensions/search.mdx create mode 100644 apps/docs/extensions/shape-container.mdx create mode 100644 apps/docs/extensions/shape-textbox.mdx create mode 100644 apps/docs/extensions/slash-menu.mdx create mode 100644 apps/docs/extensions/strike.mdx create mode 100644 apps/docs/extensions/structured-content.mdx create mode 100644 apps/docs/extensions/tab.mdx create mode 100644 apps/docs/extensions/table-cell.mdx create mode 100644 apps/docs/extensions/table-header.mdx create mode 100644 apps/docs/extensions/table-row.mdx create mode 100644 apps/docs/extensions/table.mdx create mode 100644 apps/docs/extensions/text-align.mdx create mode 100644 apps/docs/extensions/text-indent.mdx create mode 100644 apps/docs/extensions/text-style.mdx create mode 100644 apps/docs/extensions/text-transform.mdx create mode 100644 apps/docs/extensions/track-changes.mdx create mode 100644 apps/docs/extensions/underline.mdx create mode 100644 apps/docs/getting-started/ai-agents.mdx create mode 100644 apps/docs/getting-started/configuration.mdx create mode 100644 apps/docs/getting-started/fonts.mdx create mode 100644 apps/docs/getting-started/frameworks/angular.mdx create mode 100644 apps/docs/getting-started/frameworks/blazor.mdx create mode 100644 apps/docs/getting-started/frameworks/nextjs.mdx create mode 100644 apps/docs/getting-started/frameworks/nuxt.mdx create mode 100644 apps/docs/getting-started/frameworks/php.mdx create mode 100644 apps/docs/getting-started/frameworks/react.mdx create mode 100644 apps/docs/getting-started/frameworks/ruby-on-rails.mdx create mode 100644 apps/docs/getting-started/frameworks/svelte.mdx create mode 100644 apps/docs/getting-started/frameworks/vanilla-js.mdx create mode 100644 apps/docs/getting-started/frameworks/vue.mdx create mode 100644 apps/docs/getting-started/import-export.mdx create mode 100644 apps/docs/getting-started/installation.mdx create mode 100644 apps/docs/getting-started/introduction.mdx rename docs/breaking-changes-v1.md => apps/docs/guides/breaking-changes-v1.mdx (98%) create mode 100644 apps/docs/guides/general/accessibility.mdx create mode 100644 apps/docs/guides/general/security.mdx create mode 100644 apps/docs/guides/general/storage.mdx create mode 100644 apps/docs/guides/migration/prosemirror.mdx rename docs/typescript-migration.md => apps/docs/guides/typescript-migration.mdx (98%) create mode 100644 apps/docs/modules/collaboration/cloud/liveblocks.mdx create mode 100644 apps/docs/modules/collaboration/cloud/tiptap-cloud.mdx create mode 100644 apps/docs/modules/collaboration/configuration.mdx create mode 100644 apps/docs/modules/collaboration/overview.mdx create mode 100644 apps/docs/modules/collaboration/quickstart.mdx create mode 100644 apps/docs/modules/collaboration/self-hosted/hocuspocus.mdx create mode 100644 apps/docs/modules/collaboration/self-hosted/overview.mdx create mode 100644 apps/docs/modules/collaboration/self-hosted/superdoc-yjs.mdx create mode 100644 apps/docs/modules/collaboration/self-hosted/y-sweet.mdx create mode 100644 apps/docs/modules/comments.mdx create mode 100644 apps/docs/modules/overview.mdx create mode 100644 apps/docs/modules/toolbar.mdx create mode 100644 apps/docs/openapi.json create mode 100644 apps/docs/package.json create mode 100644 apps/docs/public/icons/react.svg create mode 100644 apps/docs/public/icons/vanilla-js.svg create mode 100644 apps/docs/public/icons/vue.svg create mode 100644 apps/docs/public/images/extensions/dropcursor.svg create mode 100644 apps/docs/public/images/extensions/dropcursor2.svg create mode 100644 apps/docs/public/images/extensions/image-chart.png create mode 100644 apps/docs/public/images/extensions/image-icon.png create mode 100644 apps/docs/public/images/extensions/image-landscape.png create mode 100644 apps/docs/public/images/favicon.png create mode 100644 apps/docs/public/images/logo-dark.png create mode 100644 apps/docs/public/images/logo-light.png create mode 100644 apps/docs/public/images/og-image.png create mode 100644 apps/docs/public/images/og-image2.png create mode 100644 apps/docs/public/images/og-image3.png create mode 100644 apps/docs/public/images/template-builder/demo.gif create mode 100644 apps/docs/public/images/twitter-image.png create mode 100644 apps/docs/resources/guides.mdx create mode 100644 apps/docs/resources/license.mdx create mode 100644 apps/docs/scripts/add-keywords.js create mode 100755 apps/docs/scripts/sync-api-docs.js create mode 100644 apps/docs/scripts/sync-sdk-docs.js create mode 100644 apps/docs/snippets/components/source-code-link.jsx create mode 100644 apps/docs/snippets/components/superdoc-editor.jsx create mode 100644 apps/docs/snippets/extensions/block-node.mdx create mode 100644 apps/docs/snippets/extensions/bold.mdx create mode 100644 apps/docs/snippets/extensions/bookmarks.mdx create mode 100644 apps/docs/snippets/extensions/bullet-list.mdx create mode 100644 apps/docs/snippets/extensions/color.mdx create mode 100644 apps/docs/snippets/extensions/content-block.mdx create mode 100644 apps/docs/snippets/extensions/custom-selection.mdx create mode 100644 apps/docs/snippets/extensions/document-section.mdx create mode 100644 apps/docs/snippets/extensions/document.mdx create mode 100644 apps/docs/snippets/extensions/dropcursor.mdx create mode 100644 apps/docs/snippets/extensions/font-family.mdx create mode 100644 apps/docs/snippets/extensions/font-size.mdx create mode 100644 apps/docs/snippets/extensions/format-commands.mdx create mode 100644 apps/docs/snippets/extensions/gapcursor.mdx create mode 100644 apps/docs/snippets/extensions/heading.mdx create mode 100644 apps/docs/snippets/extensions/highlight.mdx create mode 100644 apps/docs/snippets/extensions/history.mdx create mode 100644 apps/docs/snippets/extensions/image.mdx create mode 100644 apps/docs/snippets/extensions/italic.mdx create mode 100644 apps/docs/snippets/extensions/line-break.mdx create mode 100644 apps/docs/snippets/extensions/line-height.mdx create mode 100644 apps/docs/snippets/extensions/link.mdx create mode 100644 apps/docs/snippets/extensions/linked-styles.mdx create mode 100644 apps/docs/snippets/extensions/list-item.mdx create mode 100644 apps/docs/snippets/extensions/mention.mdx create mode 100644 apps/docs/snippets/extensions/node-resizer.mdx create mode 100644 apps/docs/snippets/extensions/ordered-list.mdx create mode 100644 apps/docs/snippets/extensions/page-number.mdx create mode 100644 apps/docs/snippets/extensions/paragraph.mdx create mode 100644 apps/docs/snippets/extensions/placeholder.mdx create mode 100644 apps/docs/snippets/extensions/popover-plugin.mdx create mode 100644 apps/docs/snippets/extensions/run-item.mdx create mode 100644 apps/docs/snippets/extensions/search.mdx create mode 100644 apps/docs/snippets/extensions/shape-container.mdx create mode 100644 apps/docs/snippets/extensions/shape-textbox.mdx create mode 100644 apps/docs/snippets/extensions/slash-menu.mdx create mode 100644 apps/docs/snippets/extensions/strike.mdx create mode 100644 apps/docs/snippets/extensions/structured-content.mdx create mode 100644 apps/docs/snippets/extensions/tab.mdx create mode 100644 apps/docs/snippets/extensions/table-cell.mdx create mode 100644 apps/docs/snippets/extensions/table-header.mdx create mode 100644 apps/docs/snippets/extensions/table-row.mdx create mode 100644 apps/docs/snippets/extensions/table.mdx create mode 100644 apps/docs/snippets/extensions/text-align.mdx create mode 100644 apps/docs/snippets/extensions/text-indent.mdx create mode 100644 apps/docs/snippets/extensions/text-style.mdx create mode 100644 apps/docs/snippets/extensions/text-transform.mdx create mode 100644 apps/docs/snippets/extensions/underline.mdx create mode 100644 apps/docs/solutions/esign/api-reference.mdx create mode 100644 apps/docs/solutions/esign/backend.mdx create mode 100644 apps/docs/solutions/esign/configuration.mdx create mode 100644 apps/docs/solutions/esign/introduction.mdx create mode 100644 apps/docs/solutions/esign/quickstart.mdx create mode 100644 apps/docs/solutions/overview.mdx create mode 100644 apps/docs/solutions/template-builder/api-reference.mdx create mode 100644 apps/docs/solutions/template-builder/configuration.mdx create mode 100644 apps/docs/solutions/template-builder/introduction.mdx create mode 100644 apps/docs/solutions/template-builder/quickstart.mdx create mode 100644 apps/docs/style.css diff --git a/.github/workflows/docs-validation.yml b/.github/workflows/docs-validation.yml new file mode 100644 index 0000000000..1a91c7f03a --- /dev/null +++ b/.github/workflows/docs-validation.yml @@ -0,0 +1,34 @@ +name: Documentation Validation + +on: + pull_request: + paths: + - 'apps/docs/**' + workflow_dispatch: + +jobs: + validate: + name: Validate Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'pnpm' + + - name: Install Dependencies + run: pnpm install --frozen-lockfile + + - name: Validate Docs + run: pnpm --filter @superdoc/docs validate + + - name: Check Broken Links + run: pnpm --filter @superdoc/docs check:links diff --git a/.github/workflows/trigger-docs-update.yml b/.github/workflows/trigger-docs-update.yml deleted file mode 100644 index a9bc1e5980..0000000000 --- a/.github/workflows/trigger-docs-update.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: πŸ“š Trigger Docs Update [auto] -permissions: - contents: read - -on: - release: - types: [published] - workflow_dispatch: - inputs: - version_tag: - description: "Version tag name (e.g., v0.21, v1.0)" - required: true - type: string - -jobs: - trigger-docs: - runs-on: ubuntu-latest - if: ${{ !github.event.release.prerelease }} # only trigger for stable releases - steps: - - name: Trigger documentation update - run: | - curl -L \ - -X POST \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${{ secrets.SUPERDOC_PAT }}" \ - https://api.github.com/repos/Harbour-Enterprises/SuperDoc-Docs/dispatches \ - -d '{"event_type": "docs-update", "client_payload": {"version": "${{ github.event.release.tag_name }}"}}' diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore new file mode 100644 index 0000000000..815c6f415a --- /dev/null +++ b/apps/docs/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +node_modules/ +.env +dev/ +.vscode/ \ No newline at end of file diff --git a/apps/docs/README.md b/apps/docs/README.md new file mode 100644 index 0000000000..bee32c5373 --- /dev/null +++ b/apps/docs/README.md @@ -0,0 +1,147 @@ +# SuperDoc Documentation + +A unified documentation site for both the SuperDoc JavaScript SDK and REST API, built with Mintlify. + +## Quick Start + +```bash +# Install dependencies +pnpm install + +# Start development server +pnpm dev + +# Visit http://localhost:3000 +``` + +## Project Structure + +``` +β”œβ”€β”€ introduction.mdx # Landing page +β”œβ”€β”€ quickstart.mdx # Quick start guide +β”œβ”€β”€ setup/ # Installation and configuration +β”œβ”€β”€ extensions/ # Extension docs [auto-generated] +β”‚ β”œβ”€β”€ field-annotation.mdx +β”‚ β”œβ”€β”€ track-changes.mdx +β”‚ β”œβ”€β”€ comments.mdx +β”‚ └── document-section.mdx +β”œβ”€β”€ collaboration/ # Collaboration features +β”œβ”€β”€ customization/ # Customization guides +β”œβ”€β”€ framework/ # Framework integrations +β”œβ”€β”€ advanced/ # Advanced topics +β”œβ”€β”€ api-reference/ # API documentation [auto-generated] +└── scripts/ # Sync scripts + β”œβ”€β”€ sync-api-docs.js + └── sync-sdk-docs.js +``` + +## Development + +### Available Scripts + +- `pnpm dev` - Start Mintlify development server +- `pnpm build` - Build documentation for production +- `pnpm sync:api` - Sync API documentation from OpenAPI spec +- `pnpm sync:sdk` - Sync SDK documentation from TypeDoc +- `pnpm sync:all` - Sync both API and SDK documentation +- `pnpm test:local` - Test the documentation locally + +### Testing Documentation Locally + +```bash +# Test the sync process locally +pnpm test:local +``` + +### Manual Sync from Local Repositories + +```bash +# Sync from a local SuperDoc repository +node scripts/sync-sdk-docs.js ../SuperDoc/packages/super-editor/src/extensions + +# Sync API documentation +pnpm sync:api +``` + +## Writing Documentation + +### Manual Pages + +Create MDX files in the appropriate directories: + +```mdx +--- +title: Page Title +description: Page description +--- + +# Content here + + + Use Mintlify components for rich content + +``` +More info on MDX: https://mintlify.com/docs/text + +### Extension Documentation (Auto-generated) + +Extension docs are **auto-generated** from JSDoc comments in the SuperDoc repository. + +**Do not edit files in `/extensions` directly** - they will be overwritten. + +To update extension documentation: +1. Edit JSDoc comments in SuperDoc repo +2. Push to main branch +3. Documentation updates automatically + +#### JSDoc Format + +```javascript +/** + * Extension description + * @since 1.0.0 + * @module ExtensionName + */ +export const ExtensionName = Extension.create({ + addCommands() { + return { + /** + * Command description + * @param {string} param - Parameter description + * @returns {boolean} Success status + * @example + * editor.commands.myCommand('value') + */ + myCommand: (param) => {}, + }; + }, +}); +``` + +## Versioning + +Documentation follows [Semantic Versioning](https://semver.org/) with automated releases via [semantic-release](https://github.com/semantic-release/semantic-release). + +### Conventional Commits + +Use conventional commit format to trigger automatic version bumps: + +- `docs: fix typo in API guide` β†’ patch (0.0.1 β†’ 0.0.2) +- `feat: add webhooks section` β†’ minor (0.0.1 β†’ 0.1.0) +- `feat!: restructure navigation` β†’ major (0.0.1 β†’ 1.0.0) +- `chore: update workflow` β†’ no release + +Releases are created automatically on push to `main`, updating `CHANGELOG.md`, `package.json`, and creating GitHub releases. + +## Automatic Updates & CI/CD + +The documentation automatically syncs with upstream repositories: + +1. **Changes in SuperDoc repo** - When extension files change in the main repository +2. **Manual trigger** - Via GitHub Actions UI +3. **API updates** - When OpenAPI spec changes + +### GitHub Secrets Required + +- `MINTLIFY_API_KEY` - From Mintlify dashboard +- `GH_PAT` - Personal access token for releases and commits \ No newline at end of file diff --git a/apps/docs/ai/ai-actions/configuration.mdx b/apps/docs/ai/ai-actions/configuration.mdx new file mode 100644 index 0000000000..24b122d285 --- /dev/null +++ b/apps/docs/ai/ai-actions/configuration.mdx @@ -0,0 +1,376 @@ +--- +title: Configuration +keywords: "ai actions configuration, ai workflow setup, llm integration options, automation settings, ai agent config" +--- + +AI Actions requires two pieces of configuration: a user identity for AI-generated changes and a provider for LLM completions. + +## Required options + + + Identifies the AI assistant in tracked changes and comments. + + ```ts + user: { + displayName: 'RedlineBot', + userId: 'ai-assistant', // required + profileUrl: 'https://...' // optional + } + ``` + + + + The LLM backend used for completions and streaming. Can be a provider configuration object (OpenAI, Anthropic, HTTP) or a custom provider instance. See [Provider Configuration](#provider-configuration) below. + + +## Optional options + + + Overrides the default SuperDoc-centric system message. Use this to customize how the AI interprets document context and user instructions. + + + + Emits parsing and traversal warnings to the console for debugging purposes. + + + + Maximum number of characters from the document that will accompany AI prompts. Used to control context size for both regular actions and planner operations. + + + + Configuration for the AI Planner, which enables multi-step AI workflows. See [Planner Configuration](#planner-configuration) below. + + + + Lifecycle callback fired when the AI is initialized and ready. See [Hooks](./hooks.mdx) for details. + + + + Lifecycle callback fired when streaming begins. See [Hooks](./hooks.mdx) for details. + + + + Lifecycle callback fired for each streaming chunk. See [Hooks](./hooks.mdx) for details. + + + + Lifecycle callback fired when streaming completes. See [Hooks](./hooks.mdx) for details. + + + + Lifecycle callback fired when an error occurs. See [Hooks](./hooks.mdx) for details. + + +## Provider configuration + +`provider` accepts either a config object (OpenAI, Anthropic, HTTP) or a custom implementation that exposes `getCompletion` and `streamCompletion`. + + +**Browser vs Server:** For browser applications, use the HTTP gateway pattern to keep API keys secure on your backend. OpenAI and Anthropic providers are for server-side use only (Next.js API routes, Node.js scripts, etc.). + + +### HTTP gateway (Browser-safe) + +Recommended for browser applications. Your backend handles API keys securely: + +```ts +const ai = new AIActions(superdoc, { + user, + provider: { + type: 'http', + url: '/api/ai/complete', // Your backend endpoint + headers: { + 'Authorization': `Bearer ${userAuthToken}`, + }, + }, +}); +``` + +For custom AI gateways or internal endpoints with advanced configuration: + +```ts +provider: { + type: 'http', + url: 'https://your-ai-gateway/complete', + + // Optional configuration + streamUrl: 'https://your-ai-gateway/stream', + method: 'POST', + streamResults: true, + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${userToken}`, + }, + buildRequestBody: ({ messages, stream, options }) => ({ + stream, + messages, + model: options?.model ?? 'gpt-4o-mini', + temperature: options?.temperature ?? 0.7, + metadata: options?.metadata, + }), + parseCompletion: payload => payload.choices?.[0]?.message?.content ?? '', + parseStreamChunk: payload => payload.choices?.[0]?.delta?.content ?? '', +} +``` + +**HTTP-specific options:** + + + Separate URL for streaming requests. If not provided, falls back to `url` for all requests. + + + + HTTP method for requests + + + + Custom function to build the request body. Receives `{ messages, stream, options }` context. + + + + Custom function to parse non-streaming responses. Receives the response payload and should return a string. + + + + Custom function to parse each streaming chunk. Receives the chunk payload and should return a string or undefined. + + +### OpenAI (Server-side only) + + +**Security:** Never use this provider in browser code. API keys will be exposed. Use the HTTP gateway pattern instead. + + +For server-side environments (Next.js API routes, Node.js, backend scripts): + +```ts +const ai = new AIActions(superdoc, { + user, + provider: { + type: 'openai', + apiKey: process.env.OPENAI_API_KEY!, + model: 'gpt-4o', + + // Optional configuration + baseURL: 'https://api.openai.com/v1', + organizationId: 'org_123', + completionPath: '/chat/completions', + temperature: 0.7, + maxTokens: 2000, + streamResults: true, + headers: { 'OpenAI-Beta': 'assistants=v2' }, + requestOptions: { /* additional OpenAI options */ }, + }, +}); +``` + +**OpenAI-specific options:** + + + Custom completion endpoint path (useful for Azure OpenAI or custom deployments) + + + + OpenAI organization ID for API requests + + + + Additional OpenAI-specific request options passed directly to the API + + +### Anthropic (Server-side only) + + +**Security:** Never use this provider in browser code. API keys will be exposed. Use the HTTP gateway pattern instead. + + +For server-side environments (Next.js API routes, Node.js, backend scripts): + +```ts +provider: { + type: 'anthropic', + apiKey: process.env.ANTHROPIC_API_KEY!, + model: 'claude-3-5-sonnet-20241022', + + // Optional configuration + baseURL: 'https://api.anthropic.com', + apiVersion: '2023-06-01', + temperature: 0.7, + maxTokens: 2000, + streamResults: true, + headers: { /* custom headers */ }, + requestOptions: { /* additional Anthropic options */ }, +} +``` + +**Anthropic-specific options:** + + + Anthropic API version to use + + + + Additional Anthropic-specific request options passed directly to the API + + +### Custom provider instance + +Bring your own provider that implements the `AIProvider` interface: + +```ts +const provider = { + streamResults: true, // optional + + async *streamCompletion(messages, options) { + // Yield tokens incrementally + yield 'Hello '; + yield 'world'; + }, + + async getCompletion(messages, options) { + // Return complete response + return 'response'; + }, +}; + +const ai = new AIActions(superdoc, { user, provider }); +``` + +## Common provider options + +All provider configurations support these common options: + + + Controls randomness (0-2). Lower values make output more focused and deterministic. + + + + Maximum tokens to generate in responses + + + + Stop sequences to end generation early + + + + When true, actions like `insertContent` and `summarize` will stream results back. Provider must support streaming. + + + + Custom HTTP headers to include in requests + + + + Custom fetch implementation (useful for Node.js environments or custom HTTP logic) + + + + Base URL for the API endpoint (OpenAI and Anthropic only) + + +## Helper functions + +### createAIProvider + +Factory function for creating providers from configuration objects. + +```ts +import { createAIProvider } from '@superdoc-dev/ai'; + +const provider = createAIProvider({ + type: 'openai', + apiKey: process.env.OPENAI_API_KEY, + model: 'gpt-4o', +}); + +// Use with AIActions +const ai = new AIActions(superdoc, { user, provider }); +``` + + +`AIActions` automatically calls `createAIProvider()` internally, so you can pass configuration objects directly. This helper is useful for creating providers outside of initialization. + + + +## Planner configuration + +The AI Planner enables multi-step AI workflows where the AI can plan and execute a sequence of actions. Configure it via the `planner` option: + +```ts +const ai = new AIActions(superdoc, { + user, + provider, + planner: { + maxContextLength: 10000, + documentContextProvider: () => customContextExtractor(), + tools: customTools, + onProgress: (event) => { + console.log('Planner progress:', event); + }, + }, +}); +``` + + + Maximum number of characters from the document that will be sent to the planner. Overrides the global `maxContextLength` for planner operations only. + + + + Custom function to extract document context. If not provided, uses the default document text extraction. Useful for filtering or transforming document content before sending to the AI. + + ```ts + documentContextProvider: () => { + // Return custom context string + return extractRelevantSections(); + } + ``` + + + + Array of custom tool definitions to extend or override built-in tools. See [Custom Tools](#custom-tools) below. + + + + Callback function that receives progress events during planner execution. See [Planner Progress Hooks](./hooks.mdx#planner-progress-hooks) for details. + + +### Custom tools + +You can extend the planner with custom tools or override built-in ones: + +```ts +import { AIToolDefinition } from '@superdoc-dev/ai'; + +const customTool: AIToolDefinition = { + name: 'customAction', + description: 'Performs a custom action on the document', + handler: async ({ instruction, context, previousResults }) => { + // Implement your custom logic + const result = await performCustomAction(instruction, context.editor); + return { + success: true, + data: result, + }; + }, +}; + +const ai = new AIActions(superdoc, { + user, + provider, + planner: { + tools: [customTool], + }, +}); +``` + +**Built-in tools available to the planner:** +- `findAll` - Find all occurrences matching a query +- `highlight` - Highlight content +- `replaceAll` - Replace all matches +- `literalReplace` - Literal text replacement +- `insertTrackedChanges` - Insert tracked changes +- `insertComments` - Insert comments +- `literalInsertComment` - Literal comment insertion +- `summarize` - Generate summaries +- `insertContent` - Insert new content +- `respond` - Provide textual response without document changes \ No newline at end of file diff --git a/apps/docs/ai/ai-actions/hooks.mdx b/apps/docs/ai/ai-actions/hooks.mdx new file mode 100644 index 0000000000..cd32be9b2c --- /dev/null +++ b/apps/docs/ai/ai-actions/hooks.mdx @@ -0,0 +1,283 @@ +--- +title: Hooks +keywords: "superdoc ai hooks, ai lifecycle events, automation callbacks, llm response handling, intelligent document triggers" +--- + +Hooks let you react to lifecycle milestones and streaming updates emitted by SuperDoc AI. + +```ts +const ai = new AIActions(superdoc, { + user, + provider, + onReady: ({ aiActions }) => console.log('AI ready', aiActions), + onStreamingStart: () => console.log('Streaming started'), + onStreamingPartialResult: ({ partialResult }) => updateLog(partialResult), + onStreamingEnd: ({ fullResult }) => console.log('Stream finished', fullResult), + onError: error => console.error('AI error', error), +}); +``` + +## Use cases + +Hooks are ideal for: + +- **Activity logs** - Track all AI operations and results +- **Streaming UI** - Update interface in real-time as text arrives +- **Progress indicators** - Show loading states during operations +- **Error tracking** - Centralize error reporting and monitoring +- **Analytics** - Measure AI performance and usage patterns +- **Status badges** - Display connection and readiness state + + +## Available hooks + +### `onReady` + +Called once the provider has been validated and the AI wrapper sets the editor user identity. + +**Parameters:** + + + Context object containing the AIActions instance + + ```ts + { aiActions: AIActions } + ``` + + +**Example:** + +```ts +onReady: ({ aiActions }) => { + console.log('AI is ready!'); + // Display "AI connected" badge + // Kick off initial prompt +} +``` + +### `onStreamingStart` + +Fires immediately before the provider call begins streaming. No parameters. + +**Example:** + +```ts +onStreamingStart: () => { + console.log('Starting to stream...'); + // Show loading indicator + // Clear previous results +} +``` + +### `onStreamingPartialResult` + +Fires for each streaming chunk received from the provider. The `partialResult` accumulates all text received so far. + +**Parameters:** + + + Context object containing the accumulated result + + ```ts + { partialResult: string } + ``` + + +**Example:** + +```ts +onStreamingPartialResult: ({ partialResult }) => { + console.log('Received:', partialResult); + // Update UI with latest text + // Use diffing to show incremental tokens +} +``` + + +The `partialResult` contains **all accumulated text** from the start of the stream, not just the latest chunk. Use diffing if you need to extract only the new content. + + +### `onStreamingEnd` + +Fires when streaming completes successfully. Receives the final result object. + +**Parameters:** + + + Context object containing the complete result + + ```ts + { fullResult: unknown } // Type varies: string for completions, Result for actions + ``` + + +**Example:** + +```ts +onStreamingEnd: ({ fullResult }) => { + console.log('Streaming complete:', fullResult); + // Hide loading indicator + // Log final result +} +``` + +## Hook execution order + +For both `streamCompletion()` calls and `ai.action.*` helpers, hooks fire in this order: + +1. **onStreamingStart** - Before provider call +2. **onStreamingPartialResult** - Multiple times during streaming +3. **onStreamingEnd** - After completion +4. **onError** - If an error occurs (instead of onStreamingEnd) + +## Planner progress hooks + +The AI Planner provides additional progress callbacks for multi-step workflows. Configure these via the `planner.onProgress` option: + +```ts +const ai = new AIActions(superdoc, { + user, + provider, + planner: { + onProgress: (event) => { + switch (event.type) { + case 'planning': + console.log('Planning:', event.message); + break; + case 'plan_ready': + console.log('Plan created:', event.plan); + break; + case 'tool_start': + console.log(`Step ${event.stepIndex}/${event.totalSteps}: ${event.tool}`); + break; + case 'tool_complete': + console.log(`Completed step ${event.stepIndex}/${event.totalSteps}`); + break; + case 'complete': + console.log('Planner finished:', event.success); + break; + } + }, + }, +}); +``` + +### Progress event types + + + Fired when the planner begins building an execution plan. + + ```ts + { type: 'planning'; message: string } + ``` + + + + Fired when the plan has been created and validated. + + ```ts + { type: 'plan_ready'; plan: AIPlan } + ``` + + + + Fired when a tool execution step begins. + + ```ts + { + type: 'tool_start'; + tool: string; + instruction: string; + stepIndex: number; + totalSteps: number; + } + ``` + + + + Fired when a tool execution step completes. + + ```ts + { + type: 'tool_complete'; + tool: string; + stepIndex: number; + totalSteps: number; + } + ``` + + + + Fired when all planner steps have finished. + + ```ts + { type: 'complete'; success: boolean } + ``` + + +**Example: Progress tracking UI** + +```ts +const ai = new AIActions(superdoc, { + user, + provider, + planner: { + onProgress: (event) => { + if (event.type === 'planning') { + setStatus('Planning workflow...'); + } else if (event.type === 'plan_ready') { + setStatus(`Executing ${event.plan.steps.length} steps...`); + } else if (event.type === 'tool_start') { + setProgress({ + current: event.stepIndex, + total: event.totalSteps, + tool: event.tool, + }); + } else if (event.type === 'complete') { + setStatus(event.success ? 'Complete' : 'Failed'); + } + }, + }, +}); +``` + +### `onError` + +Fired whenever an action or completion throws an error (network issues, invalid provider config, parser errors, etc.). + +**Parameters:** + + + The error object that was thrown + + +**Example:** + +```ts +onError: (error) => { + console.error('AI error:', error); + // Log to error tracking service + // Show user-friendly error message +} +``` + + +Errors are **re-thrown** after the hook runs, so you can still use `try/catch` around actions while logging errors centrally. + + +**Error handling pattern:** + +```ts +const ai = new AIActions(superdoc, { + user, + provider, + onError: error => captureException(error), // Centralized logging +}); + +try { + await ai.action.replace('Rewrite the conclusion'); +} catch (error) { + // Handle error in UI + // Error already logged by onError hook +} +``` \ No newline at end of file diff --git a/apps/docs/ai/ai-actions/methods.mdx b/apps/docs/ai/ai-actions/methods.mdx new file mode 100644 index 0000000000..245a4164aa --- /dev/null +++ b/apps/docs/ai/ai-actions/methods.mdx @@ -0,0 +1,618 @@ +--- +title: Methods +keywords: "superdoc ai methods, ai document actions, automation commands, llm task api, docx ai controls" +--- + +Reference for AIActions helpers and the high-level action surface. + +`AIActions` exposes two layers of functionality: + +1. **Wrapper methods** on the `AIActions` instance (lifecycle & raw completions). +2. **Action helpers** under `ai.action`, which combine prompting, response parsing, and editor updates. + +## Instance methods + +### `waitUntilReady` + +Resolves once provider/user set-up completes. Safe to call multiple times. + +**Returns:** `Promise` + +**Example:** + +```ts +await ai.waitUntilReady(); +console.log('AI is ready!'); +``` + +### `getIsReady` + +Returns `true` after initialisation. + +**Returns:** `boolean` + +**Example:** + +```ts +if (ai.getIsReady()) { + console.log('AI is ready!'); +} +``` + +### `getCompletion` + +Single-shot completion that includes the serialized document context. + +**Parameters:** + + + The user prompt for the AI + + + + Optional completion configuration + + +**Returns:** `Promise` + +**Example:** + +```ts +const response = await ai.getCompletion('Summarise the introduction', { + temperature: 0.3, + maxTokens: 600, + stop: [''], + metadata: { documentId: 'contract-42' }, + providerOptions: { top_p: 0.9 }, +}); +``` + +### `streamCompletion` + +Streams a completion, firing hooks for each chunk and resolving with the full string. + +**Parameters:** + + + The user prompt for the AI + + + + Optional streaming configuration + + +**Returns:** `Promise` + +**Example:** + +```ts +const response = await ai.streamCompletion('Explain the GDPR section', { + temperature: 0.7, + maxTokens: 1000, +}); +``` + +### `getDocumentContext` + +Retrieves the current document context for AI processing. Returns the plain text content of the active editor document. + +**Returns:** `string` + +**Example:** + +```ts +const context = ai.getDocumentContext(); +console.log('Document text:', context); +``` + +## Action helpers + +All actions return a [`Result`](#result) object containing `{ success: boolean; results: FoundMatch[] }`. Each [`FoundMatch`](#foundmatch) includes the AI text (`originalText`, `suggestedText`) alongside the resolved document positions. + +### `find` + +Finds the first occurrence and resolves its document positions. + +**Parameters:** + + + AI instruction describing what to find + + +**Returns:** `Promise` + +**Example:** + +```ts +const { success, results } = await ai.action.find('GDPR clause'); +if (success && results[0]?.positions?.length) { + console.log('Found at', results[0].positions[0]); +} +``` + +### `findAll` + +Finds every occurrence matching the instruction. + +**Parameters:** + + + AI instruction describing what to find + + +**Returns:** `Promise` + +### `highlight` + +Highlights the first match in the editor with the specified color. + +**Parameters:** + + + AI instruction describing what to highlight + + + + Hex color code for the highlight + + +**Returns:** `Promise` + +### `replace` + +Replaces a single match with AI-generated text. + +**Parameters:** + + + AI instruction describing what to replace and how + + +**Returns:** `Promise` + +**Example:** + +```ts +await ai.action.replace('Replace "utilize" with "use"'); +``` + +> **Note:** Replacements are inserted as fresh text, so existing styling (bold, numbering, etc.) might not carry over. Re-apply any required formatting after the AI edit. + +### `replaceAll` + +Replaces every match with AI-generated text. + +**Parameters:** + + + AI instruction describing what to replace and how + + +**Returns:** `Promise` + +### `literalReplace` + +Performs literal text replacement when you have exact find and replace text. Prefer this over `replaceAll` when the user provides explicit text pairs (e.g., "change X to Y", "replace A with B"). Automatically replaces all instances. + +**Parameters:** + + + Exact text to find + + + + Exact replacement text + + + + Optional replacement options + + ```ts + { + caseSensitive?: boolean; // Default: false + trackChanges?: boolean; // Default: false + } + ``` + + +**Returns:** `Promise` + +**Example:** + +```ts +// Direct replacement +await ai.action.literalReplace('CompanyA', 'CompanyB'); + +// Case-sensitive replacement with tracked changes +await ai.action.literalReplace('utilize', 'use', { + caseSensitive: true, + trackChanges: true +}); +``` + +### `insertTrackedChange` + +Inserts a tracked change attributed to the configured user (e.g., "RedlineBot"). + +**Parameters:** + + + AI instruction describing what change to track + + +**Returns:** `Promise` + +**Example:** + +```ts +await ai.action.insertTrackedChange( + 'Rewrite the GDPR clause as bullet points' +); +``` + +> **Note:** Tracked changes are also inserted as newly generated text, which can strip local formatting. Double-check for styling regressions after accepting or rejecting the change. + +### `insertTrackedChanges` + +Inserts tracked changes for multiple matches. + +**Parameters:** + + + AI instruction describing what changes to track + + +**Returns:** `Promise` + +### `insertComment` + +Inserts a comment annotating the first match. + +**Parameters:** + + + AI instruction describing what to comment on + + +**Returns:** `Promise` + +### `insertComments` + +Inserts comments for every match. + +**Parameters:** + + + AI instruction describing what to comment on + + +**Returns:** `Promise` + +### `literalInsertComment` + +Inserts a comment when you have exact find text and comment text. Prefer this over `insertComments` when the user provides explicit text to find and exact comment text to add. Automatically adds comments to all instances. + +**Parameters:** + + + Exact text to find + + + + Exact comment text to add + + + + Optional search options + + ```ts + { + caseSensitive?: boolean; // Default: false + } + ``` + + +**Returns:** `Promise` + +**Example:** + +```ts +// Add comment to all instances +await ai.action.literalInsertComment('GDPR', 'Please review GDPR compliance'); + +// Case-sensitive search +await ai.action.literalInsertComment('CompanyA', 'Verify entity name', { + caseSensitive: true +}); +``` + +### `summarize` + +Returns AI-generated summary text in the `suggestedText` field. Streams results if the provider supports streaming. + +**Parameters:** + + + AI instruction describing what to summarize + + +**Returns:** `Promise` + +**Example:** + +```ts +const { results } = await ai.action.summarize('Summarize the introduction'); +console.log(results[0]?.suggestedText); +``` + +### `insertContent` + +Inserts AI-generated content into the document at the current cursor position, or appends it to the end if no cursor location is set. Content streams directly into the editor as it arrives from the provider. + +**Parameters:** + + + AI instruction describing what content to insert + + + + Optional insertion options + + ```ts + { + position?: 'before' | 'after' | 'replace'; // Default: 'after' + } + ``` + + +**Returns:** `Promise` + +**Example:** + +```ts +// Insert after cursor +await ai.action.insertContent('Add a conclusion paragraph'); + +// Insert before cursor +await ai.action.insertContent('Add an introduction', { position: 'before' }); + +// Replace selection +await ai.action.insertContent('Rewrite this section', { position: 'replace' }); +``` + +## AI Planner + +The AI Planner enables multi-step AI workflows where the AI can plan and execute a sequence of actions automatically. + +### `planner` + +Access the planner instance via the `planner` property. The planner is lazily initialized on first access. + +**Returns:** `AIPlanner` + +**Example:** + +```ts +const ai = new AIActions(superdoc, { user, provider }); + +// Access the planner +const result = await ai.planner.execute('Review the document and add comments to all legal terms'); +``` + +### `planner.execute` + +Executes a user instruction by having the AI plan and execute a sequence of actions. + +**Parameters:** + + + Natural language instruction describing the multi-step task to perform + + + + Optional completion configuration for the planning phase + + +**Returns:** `Promise` + +**Result structure:** + +```ts +{ + success: boolean; + executedTools: string[]; // Names of tools that were executed + reasoning?: string; // AI's reasoning for the plan + response?: string; // Final response from the AI + plan?: AIPlan; // The execution plan that was created + rawPlan?: string; // Raw plan text from the AI + error?: string; // Error message if execution failed + warnings?: string[]; // Warnings encountered during execution +} +``` + +**Example:** + +```ts +const result = await ai.planner.execute('Fix all grammar issues and add comments to unclear sentences'); + +if (result.success) { + console.log('Executed tools:', result.executedTools); + console.log('AI reasoning:', result.reasoning); + console.log('Final response:', result.response); +} else { + console.error('Planner failed:', result.error); + console.log('Warnings:', result.warnings); +} +``` + +**Use cases:** +- Complex multi-step document reviews +- Automated document improvement workflows +- Batch operations across multiple document sections +- Conditional workflows based on document content + + +The planner automatically selects and sequences the appropriate tools based on your instruction. You don't need to specify which tools to use - the AI decides the best approach. + + +## Types + +### Result + +```ts +{ + success: boolean; + results: FoundMatch[]; +} +``` + +Standard result structure returned by all AI actions. + +### FoundMatch + +```ts +{ + originalText?: string; + suggestedText?: string; + positions?: DocumentPosition[]; +} +``` + +Represents a match found by AI operations, with optional original text, suggested replacement, and document positions. + +### DocumentPosition + +```ts +{ + from: number; + to: number; +} +``` + +Position range in the document (character offsets). + +### CompletionOptions + +```ts +{ + temperature?: number; + maxTokens?: number; + stop?: string[]; + model?: string; + signal?: AbortSignal; // Cancel request + metadata?: Record; // Custom metadata + providerOptions?: Record; // Provider-specific options + documentId?: string; // Document tracking +} +``` + +Configuration options for `getCompletion()` calls. + +### StreamOptions + +```ts +{ + temperature?: number; + maxTokens?: number; + stop?: string[]; + model?: string; + signal?: AbortSignal; // Cancel request + metadata?: Record; // Custom metadata + providerOptions?: Record; // Provider-specific options + documentId?: string; // Document tracking + stream?: boolean; // Force streaming on/off +} +``` + +Configuration options for `streamCompletion()` calls. Extends `CompletionOptions` with a `stream` flag. + +## Tool utilities + +The package exports utilities for working with AI tools and the tool registry: + +### `createToolRegistry` + +Creates a tool registry with built-in and custom tools. Used internally by the planner but can be used for custom implementations. + +**Parameters:** + + + AI actions service instance + + + + Optional array of custom tool definitions + + +**Returns:** `Map` + +**Example:** + +```ts +import { createToolRegistry, AIActionsService } from '@superdoc-dev/ai'; + +const service = new AIActionsService(provider, editor, getContext, false); +const registry = createToolRegistry(service, [ + { + name: 'customTool', + description: 'My custom tool', + handler: async ({ instruction, context }) => { + // Custom implementation + return { success: true }; + }, + }, +]); +``` + +### `getToolDescriptions` + +Gets formatted descriptions of all tools in a registry for use in system prompts. + +**Parameters:** + + + Tool registry map + + +**Returns:** `string` + +**Example:** + +```ts +import { getToolDescriptions } from '@superdoc-dev/ai'; + +const descriptions = getToolDescriptions(registry); +// Returns: "- findAll: Find all occurrences...\n- highlight: Highlight content..." +``` + +### `isValidTool` + +Type guard to validate if a value is a valid tool definition. + +**Parameters:** + + + Value to validate + + +**Returns:** `boolean` + +**Example:** + +```ts +import { isValidTool } from '@superdoc-dev/ai'; + +if (isValidTool(myTool)) { + // TypeScript knows myTool is AIToolDefinition + console.log(myTool.name, myTool.description); +} +``` + +## Advanced Exports + +For advanced use cases, the package exports additional classes and utilities: + +- **`AIActionsService`** - Core service with direct access to action implementations +- **`EditorAdapter`** - Editor interaction layer for custom integrations +- **`createAIProvider(config)`** - Factory function for creating AI providers +- **Utilities**: `validateInput()`, `parseJSON()`, `removeMarkdownCodeBlocks()`, `generateId()` diff --git a/apps/docs/ai/ai-actions/overview.mdx b/apps/docs/ai/ai-actions/overview.mdx new file mode 100644 index 0000000000..3bf8c6c8cc --- /dev/null +++ b/apps/docs/ai/ai-actions/overview.mdx @@ -0,0 +1,181 @@ +--- +title: AI Actions +sidebarTitle: Overview +keywords: "ai actions, ai document automation, high-level ai operations, intelligent docx automation, ai-driven editing" +--- + +AI Actions provides ready-to-use AI operations for SuperDoc. Run natural-language commands to find, replace, insert tracked changes, and add comments while preserving the formatting of the content being editedβ€”including heading levels and paragraph styles. Works with OpenAI, Anthropic, or custom providers. Includes the AI Planner for multi-step workflows and lower-level utilities for advanced use cases. + +## Quick start + +```ts +import { SuperDoc } from 'superdoc'; +import { AIActions, HttpProviderConfig } from '@superdoc-dev/ai'; + +const superdoc = new SuperDoc({ /* editor config */ }); + +const providerConfig: HttpProviderConfig = { + type: 'http', + url: '/api/ai/complete', // Your backend endpoint + headers: { + 'Authorization': `Bearer ${userAuthToken}`, // Your user's session token + }, +}; + +const ai = new AIActions(superdoc, { + user: { displayName: 'RedlineBot', userId: 'ai-assistant' }, + provider: providerConfig, +}); + +await ai.waitUntilReady(); + +// Use AI actions +await ai.action.find('GDPR clause'); +await ai.action.replace('Rewrite as bullet points'); +await ai.action.insertTrackedChange('Add legal disclaimer'); +``` + +Real-world examples: + +```ts +await ai.action.insertTrackedChange( + "Replace all occurrences of 'Acme Corp' with 'Acme Corporation' throughout the document" +); +``` + +```ts +await ai.action.replace( + 'Rewrite this section to improve clarity while preserving the existing formatting' +); +``` + +Formatting results depend on the source DOCX styles; list indentation may vary and may require follow-up instructions. + +## What it is + +AI Actions is SuperDoc's **high-level AI offering**. It provides pre-built operations for common document automation tasks: + +Use `insertTrackedChange` when edits should be reviewed (e.g. legal or branding updates); use `replace` for final text changes. + +- AI-powered search, rewrites, and summaries +- Tracked changes and comments created by an AI assistant +- Bulk edits and repetitive automation +- Multi-provider support (OpenAI, Anthropic, custom) + +For low-level control and custom AI workflows, [AI Builder](/ai/ai-builder/overview) is coming soon. + +## Capabilities + +- **Natural-language operations** - Find, replace, highlight, and manipulate content using plain English +- **Formatting-safe edits** - Keeps existing Word headings, custom styles, and document structure intact while modifying text +- **Tracked changes & comments** - AI-generated edits attributed to your configured AI user +- **Summaries & completions** - Generate summaries or free-form content with streaming support +- **Provider-agnostic** - Works with OpenAI, Anthropic, custom HTTP gateways, or custom providers +- **Lifecycle hooks** - Real-time callbacks for streaming, errors, and readiness +- **AI Planner** - Multi-step AI workflows with planning and execution capabilities +- **Advanced utilities** - Lower-level exports for custom implementations and tool management + +AI Actions operate on the document’s semantic structure (paragraphs, headings, lists) rather than regenerating layout, so existing styles are preserved unless explicitly changed by the instruction. + +## Lifecycle & readiness + +```ts +const ai = new AIActions(superdoc, { user, provider }); + +await ai.waitUntilReady(); + +if (!ai.getIsReady()) { + // surface UI state, retry later +} +``` + +Each action internally calls `waitUntilReady`, so explicit checks are only required when guarding UI or retry flows. + +## Error handling + +```ts +try { + await ai.action.replace('Make the GDPR clause bullet pointed'); +} catch (error) { + if (/not ready/i.test((error as Error).message)) { + await ai.waitUntilReady(); + } else { + console.error('[AIActions] replace failed', error); + } +} +``` + +Enable verbose logging by setting `enableLogging: true`. The package will emit parsing and traversal issues to `console.error`. + +## Advanced Exports + +The package exports additional utilities for advanced use cases: + +### Provider Factory + +```ts +import { createAIProvider } from '@superdoc-dev/ai'; + +// Create a provider from configuration +const provider = createAIProvider({ + type: 'openai', + apiKey: 'sk-...', + model: 'gpt-4', +}); + +// Or pass an already-instantiated provider +const customProvider = createAIProvider(myCustomProvider); +``` + +### AI Planner + +For multi-step AI workflows with planning capabilities: + +```ts +import { AIActions, AIPlannerConfig } from '@superdoc-dev/ai'; + +const ai = new AIActions(superdoc, { user, provider }); + +// Use the built-in planner +const result = await ai.planner.execute('Review the document and add comments to all legal terms'); +``` + +### 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 + +Utilities for working with AI tools: + +```ts +import { createToolRegistry, getToolDescriptions, isValidTool } from '@superdoc-dev/ai'; + +const registry = createToolRegistry(toolDefinitions); +const descriptions = getToolDescriptions(registry); + +// Validate a tool definition object +const myTool = { + name: 'myCustomTool', + description: 'My custom tool description', + handler: async ({ instruction }) => ({ success: true }) +}; +const isValid = isValidTool(myTool); +``` + +### Type Exports + +The package exports comprehensive TypeScript types including: +- `AIPlannerConfig`, `AIPlannerExecutionResult`, `AIPlan` - Planner types +- `AIToolActions`, `SelectionRange`, `SelectionSnapshot` - Tool and selection types +- `AIProviderInput`, `OpenAIProviderConfig`, `AnthropicProviderConfig`, `HttpProviderConfig` - Provider configuration types +- `PlannerContextSnapshot`, `BuilderPlanResult` - Advanced workflow types + +## Documentation + +- **[Configuration](./configuration)** - Provider setup and configuration options +- **[Methods](./methods)** - Instance methods and AI actions +- **[Hooks](./hooks)** - Lifecycle and streaming callbacks diff --git a/apps/docs/ai/ai-builder/overview.mdx b/apps/docs/ai/ai-builder/overview.mdx new file mode 100644 index 0000000000..f7333223b7 --- /dev/null +++ b/apps/docs/ai/ai-builder/overview.mdx @@ -0,0 +1,26 @@ +--- +title: AI Builder +sidebarTitle: Overview +keywords: "ai builder, low-level ai primitives, custom ai workflows, ai toolkit, document intelligence" +--- + + +**Coming Soon** - AI Builder is currently in development. Use [AI Actions](/ai/ai-actions/overview) for ready-to-use AI operations. + + +AI Builder provides low-level primitives for building custom AI workflows with SuperDoc. Create your own AI agents, specialized document intelligence features, and proprietary automation logic. + +## AI Actions is available now + +While AI Builder is in development, you can use [AI Actions](/ai/ai-actions/overview) for: + +- Find, replace, highlight operations +- Tracked changes and comments +- Document summaries and content generation +- Multi-provider support (OpenAI, Anthropic, custom) + +See the [AI Actions Quick Start](/ai/ai-actions/overview#quick-start) to get started in minutes. + +## 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). diff --git a/apps/docs/api-reference/authentication.mdx b/apps/docs/api-reference/authentication.mdx new file mode 100644 index 0000000000..c681173231 --- /dev/null +++ b/apps/docs/api-reference/authentication.mdx @@ -0,0 +1,28 @@ +--- +title: Authentication +keywords: "superdoc auth, api authentication, bearer token, api key management, secure api access" +--- + +Bearer tokens. Every request needs one. + +```bash +Authorization: Bearer sd_sk_abc123xyz789 +``` + +[Get Your Key - Takes 2 minutes](/api-reference/quickstart) + +## Production Setup + + +Client-side JavaScript? Stop. Keys belong in environment variables. + + +```bash +# .env +SUPERDOC_API_KEY=sd_sk_production_key + +# Your backend +const apiKey = process.env.SUPERDOC_API_KEY +``` + +Different keys for dev and production. Rotate quarterly. \ No newline at end of file diff --git a/apps/docs/api-reference/introduction.mdx b/apps/docs/api-reference/introduction.mdx new file mode 100644 index 0000000000..eecdf0c626 --- /dev/null +++ b/apps/docs/api-reference/introduction.mdx @@ -0,0 +1,73 @@ +--- +title: Meet our 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. + +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 + +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. + +## Base URL +``` +https://api.superdoc.dev +``` + +## Authentication + +Bearer token in every request (except `/v1/health`): + +```bash +Authorization: Bearer sd_sk_abc123xyz789 +``` + +## What's Working Now + +**Convert** - DOCX to PDF with perfect fidelity. That 50-page contract with tracked changes? Converts flawlessly. + +```bash +POST /v1/convert?from=docx +``` + +**Annotate** - Programmatically populate fields in your DOCX templates. Insert text, images, signatures, and tables. + +```bash +POST /v1/annotate +``` + +**Sign** - Add cryptographic signatures to PDFs and DOCX documents with full audit trail support. + +```bash +POST /v1/sign +``` + +**Verify** - Validate the authenticity and integrity of signed PDFs. + +```bash +POST /v1/verify +``` + +## What's Coming + +`/merge` - Combine documents with formatting intact.
+ +## Built for Real Documents + +This isn't a wrapper around LibreOffice. We built custom document processing that handles: + +- Tables spanning multiple pages +- Tracked changes from multiple reviewers +- Embedded images and charts +- 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. + +## Resources + +**[Status Page](https://status.superdoc.dev)** - Uptime and incidents +**[GitHub](https://github.com/Harbour-Enterprises/SuperDoc)** - Examples and issues diff --git a/apps/docs/api-reference/quickstart.mdx b/apps/docs/api-reference/quickstart.mdx new file mode 100644 index 0000000000..3b1482627a --- /dev/null +++ b/apps/docs/api-reference/quickstart.mdx @@ -0,0 +1,32 @@ +--- +title: Quick Start +keywords: "superdoc quickstart, api quick start, docx api tutorial, word editor guide, getting started api" +--- + +Three minutes to your first response. + + + + ```bash + curl "https://api.superdoc.dev/v1/auth/register?email=you@email.com" + ``` + Check email. Get code. + + + + ```bash + curl "https://api.superdoc.dev/v1/auth/verify?email=you@email.com&code=123456" + ``` + Save this key. We can't recover it. + + + + ```bash + curl -X POST https://api.superdoc.dev/v1/convert?from=docx \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -F "file=@contract.docx" \ + -o contract.pdf + ``` + Your DOCX is now a PDF. Tables intact. Formatting preserved. + + diff --git a/apps/docs/core/superdoc/configuration.mdx b/apps/docs/core/superdoc/configuration.mdx new file mode 100644 index 0000000000..c223ad6306 --- /dev/null +++ b/apps/docs/core/superdoc/configuration.mdx @@ -0,0 +1,357 @@ +--- +title: Configuration +keywords: "superdoc configuration, editor config options, document settings, word editor setup, api configuration" +--- + +Configuration is passed when creating a SuperDoc instance. Only two fields are required. + +## Quick Start + +```javascript +new SuperDoc({ + selector: "#editor", // Required: Where to render + document: "contract.docx", // Required: What to load +}); +``` + +## Core Parameters + + + DOM selector or element where SuperDoc will mount ```javascript selector: + '#editor' // or selector: document.querySelector('.my-editor') ``` + + + + Document to load. + + Can be a `Document (Object)`, `string` or `File` + + + - `Document` Object + ```json + { + id: 'doc-123', // string + type: 'docx', // string, can be 'docx' or 'pdf' + data: File // File or Blob + } + ``` + - `string` - URL to fetch + - `File` - From file input + + + Use `documents` array for multiple documents instead + + + + Multiple documents to load (alternative to single `document`) + + ```javascript + documents: [ + { id: 'doc-1', type: 'docx', data: fileObject }, + { id: 'doc-2', type: 'pdf', url: 'report.pdf' } + ] + ``` + + + - `File` - From file input (e.g., from ``) + - `string` (URL) - To fetch the document + + + + + Unique identifier for this SuperDoc instance + Auto-generated UUID if not provided + + +## User & Permissions + + + Current user information + + + Display name + + + Email address + + + Avatar URL + + + + + + All users with document access. Used for @mentions and collaboration. + + + + User permission level + + - `editor` - Full editing capabilities - `viewer` - Read-only access - + `suggester` - Can only suggest changes + + Role overrides documentMode when more restrictive + + + + Initial document mode + + - `editing` - Normal editing - `viewing` - Read-only display - `suggesting` + - Track changes enabled + + + + + Viewing-mode visibility controls for standard comments + + + Show comment highlights and threads when `documentMode` is `viewing` + + + + + + Viewing-mode visibility controls for tracked changes + + + Show tracked-change markup and threads when `documentMode` is `viewing` + + + + + + Override permission checks for comments and tracked changes + + ```javascript + const superdoc = new SuperDoc({ + user: { name: 'Alex Editor', email: 'alex@example.com' }, + permissionResolver: ({ permission, trackedChange, defaultDecision }) => { + if (permission === 'RESOLVE_OTHER' && trackedChange) { + return false; // Block accepting suggestions from other authors + } + return defaultDecision; + }, + }); + ``` + + Return `false` to block an action. Return `true` or `undefined` to fall back to the built-in permission matrix. + + +## Modules + + + Configure optional modules + + +### Collaboration Module + + + Real-time collaboration settings + + + WebSocket server URL + + + Provider implementation + + + Authentication token + + + Additional connection parameters + + + + +### Comments Module + + + Comments system configuration + + + DOM element for comments list + + + Allow resolving comments + + + Dual comment system + + + Comments-only override for the permission resolver + + + + +### Toolbar Module + + + Toolbar configuration + + + + Toolbar container + + + Layout groups + + + Custom icon overrides + + + Text label overrides + + + Available font families. See [Toolbar fonts](/modules/toolbar#font-configuration) for details. + + Custom fonts from DOCX files will display in the toolbar but won't be selectable unless loaded in your app and added here. + + + Hide when inactive + + + Container-based responsive sizing + + + + + +## Appearance + + + Document title for exports and display + + + + Colors for user awareness and highlighting + Built-in palette provided by default + + + + Enable page-based layout + Consider using `layoutMode` for more control over document layout + + + + Controls how the document is rendered + + - `paginated` - Fixed page width with page breaks (default) + - `responsive` - 100% width, text reflows to fit container + + Use `responsive` for mobile devices and WCAG AA accessibility compliance. When set to `responsive`, pagination is automatically disabled. + + + + Custom margins in pixels for responsive layout + + Top margin in pixels + Bottom margin in pixels + Left margin in pixels + Right margin in pixels + + Only applies when `layoutMode` is set to `responsive` + + ```javascript + layoutMargins: { top: 10, bottom: 10, left: 10, right: 10 } + ``` + + + + Show document rulers + + + + DOM element for toolbar + Alternative to `modules.toolbar.selector` + + +## Advanced Options + + + Additional SuperDoc extensions + + + + Learn how to create your own extensions + [here](/extensions/creating-extensions). + + + + Custom image upload handler + + ```javascript + handleImageUpload: async (file) => { + const formData = new FormData(); + formData.append('image', file); + const response = await fetch('/upload', { + method: 'POST', + body: formData + }); + const { url } = await response.json(); + return url; + } + ``` + + + + Telemetry configuration + + + Enable telemetry + + + License key + + + Telemetry endpoint + + + + + + Prevent default DOCX styles from being applied + + + + Disable custom context menus + + + + Content Security Policy nonce + + +## Event Handlers + +All handlers are optional functions in the configuration: + + + Called when SuperDoc is ready + + ```javascript + onReady: ({ superdoc }) => { + console.log('Ready'); + } + ``` + + + + Called when editor is created + + ```javascript + onEditorCreate: ({ editor }) => { + editor.focus(); + } + ``` + + + + Called on content changes + + ```javascript + onEditorUpdate: ({ editor }) => { + autoSave(editor.getJSON()); + } + ``` + + +See [Events](/core/superdoc/events) for complete list. diff --git a/apps/docs/core/superdoc/events.mdx b/apps/docs/core/superdoc/events.mdx new file mode 100644 index 0000000000..ffea1eb48a --- /dev/null +++ b/apps/docs/core/superdoc/events.mdx @@ -0,0 +1,328 @@ +--- +title: Events +keywords: "superdoc events, document events, editor callbacks, word editor listeners, event handling" +--- + +SuperDoc uses an event system for lifecycle hooks and change notifications. + +## Event Methods + +### Subscribe to Events + + + Event name to listen for + + + + Callback function + + +```javascript +// Regular subscription +superdoc.on('ready', handler); + +// One-time listener +superdoc.once('ready', handler); + +// Unsubscribe +superdoc.off('ready', handler); +``` + +## Event Categories + + + + Initialization and teardown + + + Document changes + + + Multi-user events + + + Interface changes + + + +## 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 +}); +``` + +### `editorCreate` + +When an editor is created. + + + Created editor instance + + +```javascript +superdoc.on('editorCreate', ({ editor }) => { + console.log('Editor created'); + editor.focus(); +}); +``` + +### `editorDestroy` + +When an editor is destroyed. + +No parameters passed + +```javascript +superdoc.on('editorDestroy', () => { + console.log('Editor destroyed'); + cleanup(); +}); +``` + +## Content Events + +### `editor-update` + +When editor content changes. + + + Editor with updated content + + +```javascript +superdoc.on('editor-update', ({ editor }) => { + const content = editor.getJSON(); + autoSave(content); +}); +``` + +### `content-error` + +When content processing fails. + + + Error details + + + + Related editor instance + + + + Document identifier + + + + Original file + + +```javascript +superdoc.on('content-error', ({ error, editor }) => { + console.error('Content error:', error); + handleError(error); +}); +``` + +### `fonts-resolved` + +When the document fonts are resolved. + + + Object with document fonts and unsupported fonts + + +```javascript +superdoc.on('fonts-resolved', ({ documentFonts, unsupportedFonts }) => { + if (unsupportedFonts.length > 0) { + console.warn('Some fonts in the document are not supported.', unsupportedFonts.join(', ')) + } +}) +``` + +## 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(); +}); +``` + +## Collaboration Events + +### `collaboration-ready` + +When collaboration is initialized. + + + Editor with collaboration + + +```javascript +superdoc.on('collaboration-ready', ({ editor }) => { + console.log('Collaboration active'); + showOnlineUsers(); +}); +``` + +### `awareness-update` + +When user presence changes. + + + Awareness context + + + + User states map + + +```javascript +superdoc.on('awareness-update', ({ context, states }) => { + const users = Array.from(states.values()); + updateUserCursors(users); +}); +``` + +### `locked` + +When document lock state changes. + + + Lock state + + + + User who locked the document + + +```javascript +superdoc.on('locked', ({ isLocked, lockedBy }) => { + if (isLocked) { + showLockBanner(`Locked by ${lockedBy.name}`); + } +}); +``` + +## Configuration-Based Events + + +Events can also be configured during initialization + + +```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 + +```javascript +import { debounce } from 'lodash'; + +const save = debounce(async (content) => { + await api.saveDocument(content); +}, 1000); + +superdoc.on('editor-update', ({ editor }) => { + save(editor.getJSON()); +}); +``` + +### Track Multiple Editors + +```javascript +const editors = new Map(); + +superdoc.on('editorCreate', ({ editor }) => { + const id = editor.options.documentId; + editors.set(id, editor); +}); + +superdoc.on('editorDestroy', () => { + editors.clear(); +}); +``` + +### Clean Up Pattern + +```javascript +const handlers = { + ready: () => console.log('Ready'), + update: () => console.log('Updated') +}; + +// Subscribe +Object.entries(handlers).forEach(([event, handler]) => { + superdoc.on(event, handler); +}); + +// Later: Unsubscribe all +Object.entries(handlers).forEach(([event, handler]) => { + superdoc.off(event, handler); +}); +``` + +## 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 diff --git a/apps/docs/core/superdoc/methods.mdx b/apps/docs/core/superdoc/methods.mdx new file mode 100644 index 0000000000..7bd266ccaf --- /dev/null +++ b/apps/docs/core/superdoc/methods.mdx @@ -0,0 +1,334 @@ +--- +title: Methods +keywords: "superdoc methods, document api methods, editor functions, word document api, programmatic control" +--- + +Methods are functions you call on the SuperDoc instance to perform actions. + +## Document Operations + +### `export` + +Export the document with various options. + + + Export configuration + + + + Export formats + + + Replace fields with values + + + Comment handling: 'external', 'clean', or custom + + + Base filename + + + Auto-download file + + + Field highlight color + + + + +**Returns:** `Promise` - Document blob + +```javascript +const blob = await superdoc.export({ + isFinalDoc: true, + commentsType: 'clean' +}); +``` + +### `save` + +Save document if in collaboration mode. + +**Returns:** `Promise` + +```javascript +await superdoc.save(); +``` + +### `getHTML` + +Get HTML content of all editors. + + + HTML options + + + + Preserve nested list structure + + + + +**Returns:** `string[]` - Array of HTML strings, one per editor + +```javascript +const htmlArray = superdoc.getHTML(); +``` + +## Mode Control + +### `setDocumentMode` + +Change the document mode. + + + New document mode + + + - `'viewing'` - Read-only + - `'suggesting'` - Track changes + - `'editing'` - Normal editing + + + +```javascript +superdoc.setDocumentMode('suggesting'); +``` + +### `lockSuperdoc` + +Lock or unlock the document. + + + Lock state + + + + User who locked the document + + +```javascript +superdoc.lockSuperdoc(true, currentUser); +``` + +### `setHighContrastMode` + +Enable/disable high contrast mode. + + + High contrast state + + +```javascript +superdoc.setHighContrastMode(true); +``` + +## UI Methods + +### `toggleRuler` + +Toggle ruler visibility. + +```javascript +superdoc.toggleRuler(); +``` + +### `togglePagination` + +Toggle pagination mode. + +```javascript +superdoc.togglePagination(); +``` + +### `focus` + +Focus the active editor or first available. + +```javascript +superdoc.focus(); +``` + +## Search Methods + +### `search` + +Search for text or regex in active editor. + + + Search query + + +**Returns:** `Array` - Search matches + +```javascript +const results = superdoc.search('contract'); +const results = superdoc.search(/section \d+/gi); +``` + +### `goToSearchResult` + +Navigate to a search result. + + + Search result to navigate to + + +```javascript +superdoc.goToSearchResult(results[0]); +``` + +## Comments Methods + +### `addCommentsList` + +Add a comments list to the specified element. + + + Container for comments list + + +```javascript +superdoc.addCommentsList('#comments-sidebar'); +``` + +### `removeCommentsList` + +Remove the comments list. + +```javascript +superdoc.removeCommentsList(); +``` + +## User Management + +### `addSharedUser` + +Add a user to the shared users list. + + + User to add + + + + Display name + + + Email address + + + + +```javascript +superdoc.addSharedUser({ + name: 'Jane Smith', + email: 'jane@example.com' +}); +``` + +### `removeSharedUser` + +Remove a user from shared users. + + + Email of user to remove + + +```javascript +superdoc.removeSharedUser('jane@example.com'); +``` + +## Lifecycle Methods + +### `destroy` + +Completely destroy the SuperDoc instance. + +This is irreversible. Cleans up all resources, events, and DOM. + +```javascript +superdoc.destroy(); +``` + +## Event Methods + +### `on` + +Subscribe to an event. + + + Event name + + + + Event handler + + +```javascript +superdoc.on('ready', ({ superdoc }) => { + console.log('SuperDoc ready'); +}); +``` + +### `once` + +Subscribe to an event once. + + + Event name + + + + Event handler + + +```javascript +superdoc.once('ready', () => { + // Only called once +}); +``` + +### `off` + +Unsubscribe from an event. + + + Event name + + + + Handler to remove + + +```javascript +superdoc.off('ready', handler); +``` + +## Method Patterns + +### Async Operations + +```javascript +async function exportDocument() { + try { + const blob = await superdoc.export({ + isFinalDoc: true + }); + saveToFile(blob); + } catch (error) { + console.error('Export failed:', error); + } +} +``` + +### Waiting for Ready + +Some methods require SuperDoc to be ready + +```javascript +superdoc.once('ready', () => { + // Now safe to use all methods + superdoc.search('term'); + superdoc.setDocumentMode('suggesting'); +}); +``` \ No newline at end of file diff --git a/apps/docs/core/superdoc/overview.mdx b/apps/docs/core/superdoc/overview.mdx new file mode 100644 index 0000000000..fc9a1232ff --- /dev/null +++ b/apps/docs/core/superdoc/overview.mdx @@ -0,0 +1,45 @@ +--- +title: SuperDoc API +sidebarTitle: Overview +keywords: "superdoc class, document editor api, docx sdk methods, word editor instance, document initialization" +--- + +The SuperDoc instance is your main interface for controlling the DOCX editor. It handles document loading, editor management, and all interactions. + +## Creating an instance + +```javascript +import { SuperDoc } from '@harbour-enterprises/superdoc'; + +const superdoc = new SuperDoc({ + selector: '#editor', + document: 'contract.docx' +}); +``` + +## Instance lifecycle + +```javascript +// 1. Creation +const superdoc = new SuperDoc(config); + +// 2. Ready event +superdoc.on('ready', () => { + // Now safe to use methods +}); + +// 3. Runtime operations +superdoc.setDocumentMode('suggesting'); +superdoc.export(); + +// 4. Cleanup +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 +- **[Events](/core/superdoc/events)** - Lifecycle and change notifications +``` diff --git a/apps/docs/core/superdoc/properties.mdx b/apps/docs/core/superdoc/properties.mdx new file mode 100644 index 0000000000..914412e38e --- /dev/null +++ b/apps/docs/core/superdoc/properties.mdx @@ -0,0 +1,273 @@ +--- +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 new file mode 100644 index 0000000000..f512ca6d3d --- /dev/null +++ b/apps/docs/core/superdoc/types.mdx @@ -0,0 +1,81 @@ +--- +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 new file mode 100644 index 0000000000..874ae10e2b --- /dev/null +++ b/apps/docs/core/supereditor/configuration.mdx @@ -0,0 +1,366 @@ +--- +title: Configuration +keywords: "supereditor config, editor configuration, prosemirror setup, document editor options, advanced config" +--- + +SuperEditor configuration gives you low-level control over the DOCX engine. + +## 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); + +// Create editor +const editor = new Editor({ + mode: "docx", + documentMode: "editing", + element: document.getElementById("editor"), + documentId: "doc-123", + extensions: getStarterExtensions(), + fileSource: docxFile, + content, + media, + mediaFiles, + fonts, +}); +``` + +## Required Parameters + + + DOM element where the editor will mount + +```javascript +element: document.getElementById("editor"); +``` + + + + + Unique identifier for this document instance. Used for collaboration and + storage. + + + + Extensions that define the editor schema and functionality. + +```javascript +import { getStarterExtensions } from "superdoc/super-editor"; + +extensions: getStarterExtensions(); +``` + + + +## DOCX Mode Parameters + + + The DOCX file to load + + + + Parsed XML content from `Editor.loadXmlData()` + + + + Media file mappings from `Editor.loadXmlData()` + + + + Media blob data from `Editor.loadXmlData()` + + + + Font configuration from `Editor.loadXmlData()` + + +## Modes & Permissions + + + Editor rendering mode + + + - `docx` - Full DOCX features + - `text` - Plain text mode + - `html` - HTML mode + + + + + Current editing state + + + - `editing` - Full editing capabilities + - `viewing` - Read-only mode + - `suggesting` - Track changes enabled + + + + + User permission level. Overrides documentMode when more restrictive. + + Role always wins over documentMode in permission conflicts + + + + Whether the editor accepts input + + +## User & Collaboration + + + Current user information + + + + Display name + + + Email address + + + Avatar URL + + + + + + All users with document access. Used for @mentions and awareness. + + + + Yjs document for real-time collaboration + + + + Provider instance for collaboration sync + + +## Content Initialization + + + Initialize with HTML content (for `mode: 'html'`) + + + + Initialize with Markdown (converts to document) + + + + Use ProseMirror JSON content instead of DOCX parsing + + +## Features + + + Enable comments system + + + + Enable field annotations + + + + Enable page-based layout + + +## Advanced Options + + + Run without mounting an editor view (Node.js/server-side processing). + You must provide `document` from JSDOM for serialization methods like `getHTML()`. + + + + DOM Document for serialization in headless mode (e.g., `window.document` from JSDOM). + + + + 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 + +```javascript +handleImageUpload: async (file) => { + const url = await uploadToS3(file); + return url; +}; +``` + + + +## Configuration Patterns + +### Full DOCX Editor + +```javascript +import "superdoc/style.css"; +import { Editor, getStarterExtensions } 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" }, + }); +} +``` + +### Headless Converter (Node.js) + +Convert DOCX files server-side without a browser using JSDOM. + + + See the [headless-converter + example](https://github.com/Harbour-Enterprises/superdoc/tree/main/examples/advanced/headless-converter) + for a complete implementation. + + +```javascript +import { readFile } from "fs/promises"; +import { JSDOM } from "jsdom"; +import { Editor, getStarterExtensions } 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, +}); + +// Output formats +const html = editor.getHTML(); +const json = editor.getJSON(); +const text = editor.state.doc.textContent; +const markdown = await editor.getMarkdown(); + +editor.destroy(); +``` + +### 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. + + +```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 +}); + +const html = editor.getHTML(); +editor.destroy(); +``` + + + The `document` option replaces the deprecated `mockDocument` and `mockWindow` options. + + +### Custom Collaboration + +```javascript +import { Editor, getStarterExtensions } 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", + element: document.getElementById("editor"), + documentId: roomId, + extensions: getStarterExtensions(), + fileSource: docxFile, + content, + media, + mediaFiles, + fonts, + ydoc: new Y.Doc(), + collaborationProvider: new HocuspocusProvider({ + url: "wss://collab.example.com", + name: roomId, + }), + user: currentUser, + users: roomUsers, +}); +``` + +### Track Changes Mode + +```javascript +const [content, media, mediaFiles, fonts] = await Editor.loadXmlData(docxFile); + +const editor = new Editor({ + mode: "docx", + documentMode: "suggesting", + element: document.getElementById("editor"), + documentId: "review-doc", + extensions: getStarterExtensions(), + fileSource: docxFile, + content, + media, + mediaFiles, + fonts, + user: reviewer, +}); +``` diff --git a/apps/docs/core/supereditor/hooks.mdx b/apps/docs/core/supereditor/hooks.mdx new file mode 100644 index 0000000000..23d064f23c --- /dev/null +++ b/apps/docs/core/supereditor/hooks.mdx @@ -0,0 +1,341 @@ +--- +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 new file mode 100644 index 0000000000..cffca31374 --- /dev/null +++ b/apps/docs/core/supereditor/methods.mdx @@ -0,0 +1,564 @@ +--- +title: Methods +keywords: "supereditor methods, editor commands, prosemirror commands, document manipulation, editor api" +--- + +SuperEditor exposes both high-level methods and direct ProseMirror access. + +## Content Methods + +### `getHTML` + +Get document as HTML string. + + + Configuration options + + + + Preserve nested list structure + + + + +**Returns:** `string` - HTML representation + +```javascript +const html = editor.getHTML(); +// With nested lists preserved +const html = editor.getHTML({ unflattenLists: true }); +``` + +### `getJSON` + +Get document as ProseMirror JSON. + +**Returns:** `Object` - ProseMirror document JSON + +```javascript +const json = editor.getJSON(); +``` + +### `getUpdatedJson` + +Get JSON prepared for export with comment processing. + +**Returns:** `Object` - Export-ready JSON + +```javascript +const json = editor.getUpdatedJson(); +``` + +## Export Methods + +### `exportDocx` + +Export document as DOCX file. + + + Export configuration + + + + Replace fields with values + + + Comment handling: 'external', 'clean', or custom + + + + Comments to include + + [Data structure](/modules/comments#comment-data-structure) + + + Field highlight color + + + + +**Returns:** `Promise` - DOCX file blob + +```javascript +const blob = await editor.exportDocx({ + isFinalDoc: true, + commentsType: 'clean' +}); +``` + +### `loadXmlData` + +Load and parse DOCX file data. + + + DOCX file source + + + + Whether running in Node.js + + +**Returns:** `Promise<[xmlFiles, mediaUrls, mediaBase64, fonts]>` + +```javascript +const [xmlFiles, mediaUrls, mediaBase64, fonts] = + await Editor.loadXmlData(docxFile); +``` + +## Editor Control + +### `mount` + +Mount editor to DOM element. + + + Target DOM element + + +```javascript +editor.mount(document.querySelector('#new-container')); +``` + +### `unmount` + +Unmount editor from DOM (keeps instance alive). + +```javascript +editor.unmount(); +``` + +### `destroy` + +Completely destroy editor and clean up. + +This is irreversible. The editor instance cannot be used after calling destroy. + +```javascript +editor.destroy(); +``` + +### `focus` + +Focus the editor. + +```javascript +editor.focus(); +``` + +### `setEditable` + +Set editor editability. + + + Whether editor should be editable + + + + Whether to emit update event + + +```javascript +editor.setEditable(false); // Read-only +editor.setEditable(true, false); // Editable without event +``` + +## Mode Control + +### `setDocumentMode` + +Change document editing mode. + + + Document mode + + + - `'viewing'` - Read-only + - `'suggesting'` - Track changes + - `'editing'` - Full editing + + + +```javascript +editor.setDocumentMode('suggesting'); +``` + +## Command Methods + +### `chain` + +Create a command chain. + +**Returns:** `ChainedCommands` - Chainable command object + +```javascript +editor.chain() + .focus() + .selectAll() + .toggleBold() + .run(); +``` + +### `can` + +Check if commands can run without executing. + +**Returns:** `Commands` - Commands in check mode + +```javascript +if (editor.can().toggleBold()) { + // Bold button should be enabled +} +``` + +### Direct Commands + +Access all commands directly. + +```javascript +editor.commands.toggleBold(); +editor.commands.insertTable({ rows: 3, cols: 3 }); +editor.commands.setTextSelection({ from: 10, to: 20 }); +``` + +### `insertContent` + +Insert content into the document with automatic format detection. + + + Content to insert (HTML, Markdown, text, or JSON) + + + + 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 + + + Where to insert (defaults to current position) + + + Update selection after insert + + + + +**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 } +}); +``` + +**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 +}); +``` + + +When importing HTML or Markdown, all inline styles are removed to ensure Word compatibility. + + +## Content Manipulation + +### `replaceContent` + +Replace entire editor content. + + + ProseMirror JSON content + + +```javascript +editor.replaceContent(newJsonContent); +``` + +### `replaceNodeWithHTML` + +Replace specific node with HTML. + + + ProseMirror node to replace + + + + HTML replacement + + +```javascript +const tableNode = editor.getNodesOfType('table')[0]; +editor.replaceNodeWithHTML(tableNode, '...
'); +``` + +### `replaceFile` + +Replace current DOCX file. + + + New DOCX file + + +**Returns:** `Promise` + +```javascript +await editor.replaceFile(newDocxFile); +``` + +## Annotation Methods + These methods are available with the [field-annotation](/extensions/field-annotation) extension. + +### `annotate` + +Apply field annotations to document. + + + Annotation values + + + + Field ID + + + Field value + + + + + + Field IDs to hide + + + + Remove empty fields + + +```javascript +editor.annotate([ + { input_id: 'field1', input_value: 'John Doe' }, + { input_id: 'field2', input_value: 'CEO' } +], ['field3'], true); +``` + +### `previewAnnotations` + +Preview annotations (reversible). + + + Annotation values + + + + Field IDs to hide + + +```javascript +editor.previewAnnotations(values, hiddenIds); +``` + +### `closePreview` + +Revert annotation preview. + +```javascript +editor.closePreview(); +``` + +## 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 + +```javascript +const tables = editor.getNodesOfType('table'); +``` + +### `isActive` + +Check if node or mark is active. + + + Node/mark name or attributes + + + + Additional attributes to check + + +**Returns:** `boolean` - Whether 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 + +```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 + + + + +**Returns:** `HTMLElement | null` - DOM element at position, or `null` if unavailable + +```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 }); +``` + + +**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: + +```javascript +editor.presentationEditor.scrollToPosition(pos); +const element = editor.getElementAtPos(pos); +``` + +To disable virtualization, use `layoutEngineOptions` when creating SuperDoc: + +```javascript +const superdoc = new SuperDoc({ + layoutEngineOptions: { + virtualization: { enabled: false } + } +}); +``` + + + +In presentation mode, this method only works in body mode. It returns `null` when editing headers or footers. + + +## 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 + diff --git a/apps/docs/core/supereditor/overview.mdx b/apps/docs/core/supereditor/overview.mdx new file mode 100644 index 0000000000..c27f4f5c8d --- /dev/null +++ b/apps/docs/core/supereditor/overview.mdx @@ -0,0 +1,87 @@ +--- +title: SuperEditor API +sidebarTitle: Overview +keywords: "supereditor class, prosemirror docx, tiptap alternative, editor commands, document manipulation api" +--- + +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 + +**Use SuperDoc (recommended):** + +- Standard DOCX editing needs +- Built-in UI and modules +- Collaboration and comments +- Quick integration + +**Use SuperEditor directly:** + +- Custom UI implementation +- Framework-specific integrations +- [Headless/server-side processing](/core/supereditor/configuration#headless-converter-nodejs) +- Custom extension development + +## 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(); +``` + +## Key Initialization Steps + +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` + +## Direct ProseMirror access + +SuperEditor gives you full ProseMirror access: + +```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); +}); +``` + +## API structure + +- **[Configuration](/core/supereditor/configuration)** - Initialization options +- **[Methods](/core/supereditor/methods)** - Control the editor +- **[Hooks](/core/supereditor/hooks)** - React to changes diff --git a/apps/docs/docs.json b/apps/docs/docs.json new file mode 100644 index 0000000000..92eee0362b --- /dev/null +++ b/apps/docs/docs.json @@ -0,0 +1,405 @@ +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "willow", + "name": "SuperDoc", + "description": "Web-based DOCX editor with full Microsoft Word compatibility. Handle tracked changes, complex tables, and document automation. Works with any framework and AI agents.", + "colors": { + "primary": "#0055FF", + "light": "#0085FF", + "dark": "#003ACC" + }, + "logo": { + "light": "/public/images/logo-light.png", + "dark": "/public/images/logo-dark.png" + }, + "favicon": "/public/images/favicon.png", + "icons": { + "library": "lucide" + }, + "fonts": { + "family": "Plus Jakarta Sans", + "body": { + "family": "Inter" + }, + "heading": { + "font-size": "2.5rem !important" + } + }, + "contextual": { + "options": [ + "copy", + "chatgpt", + "claude", + { + "title": "Ask on Discord", + "description": "Join our support channel", + "icon": "discord", + "href": "https://discord.com/channels/1299087524056010902/1299436491839246409" + } + ] + }, + "navigation": { + "tabs": [ + { + "tab": "Editor", + "groups": [ + { + "group": "Getting Started", + "pages": [ + "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" + ] + } + ] + }, + { + "group": "Core", + "pages": [ + { + "group": "SuperDoc", + "pages": [ + "core/superdoc/overview", + "core/superdoc/configuration", + "core/superdoc/methods", + "core/superdoc/events", + "core/superdoc/properties", + "core/superdoc/types" + ] + }, + { + "group": "SuperEditor", + "pages": [ + "core/supereditor/overview", + "core/supereditor/configuration", + "core/supereditor/methods", + "core/supereditor/hooks" + ] + } + ] + }, + { + "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": [ + "modules/overview", + { + "group": "Collaboration", + "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/comments", + "modules/toolbar" + ] + }, + { + "group": "Extensions", + "pages": [ + "extensions/overview", + "extensions/creating-extensions", + { + "group": "All", + "pages": [ + "extensions/block-node", + "extensions/bold", + "extensions/bullet-list", + "extensions/color", + "extensions/content-block", + "extensions/custom-selection", + "extensions/document", + "extensions/dropcursor", + "extensions/font-family", + "extensions/font-size", + "extensions/format-commands", + "extensions/gapcursor", + "extensions/heading", + "extensions/highlight", + "extensions/history", + "extensions/image", + "extensions/italic", + "extensions/line-break", + "extensions/line-height", + "extensions/link", + "extensions/linked-styles", + "extensions/list-item", + "extensions/mention", + "extensions/noderesizer", + "extensions/ordered-list", + "extensions/page-number", + "extensions/paragraph", + "extensions/placeholder", + "extensions/popover-plugin", + "extensions/run-item", + "extensions/search", + "extensions/shape-container", + "extensions/shape-textbox", + "extensions/slash-menu", + "extensions/strike", + "extensions/structured-content", + "extensions/tab", + "extensions/table", + "extensions/table-cell", + "extensions/table-header", + "extensions/table-row", + "extensions/text-align", + "extensions/text-indent", + "extensions/text-style", + "extensions/text-transform", + "extensions/underline" + ] + } + ] + }, + { + "group": "Solutions", + "pages": [ + "solutions/overview", + { + "group": "eSign", + "pages": [ + "solutions/esign/introduction", + "solutions/esign/quickstart", + "solutions/esign/configuration", + "solutions/esign/api-reference", + "solutions/esign/backend" + ] + }, + { + "group": "Template Builder", + "tag": "NEW", + "pages": [ + "solutions/template-builder/introduction", + "solutions/template-builder/quickstart", + "solutions/template-builder/configuration", + "solutions/template-builder/api-reference" + ] + } + ] + }, + { + "group": "Resources", + "pages": ["resources/guides", "resources/license"] + } + ] + }, + { + "tab": "Guides", + "groups": [ + { + "group": "General", + "pages": ["guides/general/storage", "guides/general/accessibility", "guides/general/security"] + }, + { + "group": "Migration", + "pages": ["guides/migration/prosemirror", "guides/breaking-changes-v1", "guides/typescript-migration"] + } + ] + }, + { + "tab": "Documents API", + "groups": [ + { + "group": "Getting Started", + "pages": ["api-reference/introduction", "api-reference/quickstart", "api-reference/authentication"] + }, + { + "group": "Authentication", + "openapi": "openapi.json", + "pages": ["GET /v1/auth/register", "GET /v1/auth/verify"] + }, + { + "group": "Document Operations", + "openapi": "openapi.json", + "pages": ["POST /v1/convert", "POST /v1/annotate", "POST /v1/sign", "POST /v1/verify"] + }, + { + "group": "System", + "openapi": "openapi.json", + "pages": ["GET /v1/health"] + } + ] + } + ] + }, + "api": { + "playground": { + "display": "interactive" + } + }, + "navbar": { + "primary": { + "type": "button", + "href": "https://superdoc.dev/meetings/caio-pizzol", + "label": "Talk to an engineer" + }, + "links": [ + { + "type": "button", + "href": "https://github.com/Harbour-Enterprises/SuperDoc", + "label": "", + "icon": "github" + }, + { + "type": "button", + "href": "https://discord.com/invite/b9UuaZRyaB", + "label": "", + "icon": "discord" + } + ] + }, + "redirects": [ + { + "source": "/guide/quick-start", + "destination": "/getting-started/installation" + }, + { + "source": "/guide/modes-roles", + "destination": "/core/superdoc/configuration#setting-priority" + }, + { + "source": "/guide/components", + "destination": "/core/superdoc/overview" + }, + { + "source": "/guide/field-annotation", + "destination": "/core/extensions/field-annotation" + }, + { + "source": "/guide/modules", + "destination": "/modules/overview" + }, + { + "source": "/guide/integration", + "destination": "/getting-started/installation" + }, + { + "source": "/guide/collaboration", + "destination": "/modules/collaboration" + }, + { + "source": "/guide/accessibility", + "destination": "/guides/general/accessibility" + }, + { + "source": "/resources/accessibility", + "destination": "/guides/general/accessibility" + }, + { + "source": "/resources/security", + "destination": "/guides/general/security" + }, + { + "source": "/resources/storage", + "destination": "/guides/general/storage" + }, + { + "source": "/resources/migration", + "destination": "/guides/migration/prosemirror" + }, + { + "source": "/resources/guides", + "destination": "/guides/general" + }, + { + "source": "/guide/resources#migrate-from-prosemirror", + "destination": "/guides/migration/prosemirror" + }, + { + "source": "/guide/advanced", + "destination": "/core/supereditor/overview" + }, + { + "source": "/getting-started/ai-ready", + "destination": "/getting-started/ai-agents" + }, + { + "source": "/api-reference/documents/sign", + "destination": "/api-reference/signature/sign" + }, + { + "source": "/modules/collaboration/backend", + "destination": "/modules/collaboration/self-hosted/overview" + }, + { + "source": "/modules/collaboration/client", + "destination": "/modules/collaboration/configuration" + } + ], + "integrations": { + "posthog": { + "apiHost": "https://us.i.posthog.com", + "apiKey": "phc_jBYwMLryemk0X6RErATTY6I5GSSIzmErvfMIakkfh24" + }, + "gtm": { + "tagId": "GTM-PHNMQSDL" + } + }, + "seo": { + "indexing": "all", + "metatags": { + "description": "Web-based DOCX editor with full Microsoft Word compatibility. Handle tracked changes, complex tables, and document automation. Works with any framework and AI agents.", + "keywords": "DOCX editor, Microsoft Word web editor, document automation, tracked changes, contract management, document API, Word compatibility, LLM document editing, AI document processing", + "author": "SuperDoc", + "og:type": "website", + "og:url": "https://docs.superdoc.dev", + "og:image": "public/images/og-image.png", + "og:description": "DOCX editor that handles real Microsoft Word documents on the web. Tracked changes, complex tables, full Word compatibility. Built for contract management and document automation.", + "og:site_name": "SuperDoc Documentation", + "twitter:card": "summary_large_image", + "twitter:site": "@superdocdev", + "twitter:title": "SuperDoc - Real Microsoft Word Documents on the Web", + "twitter:description": "DOCX editor with full Word compatibility. Handle tracked changes, complex tables, and document automation with AI support.", + "twitter:image": "public/images/twitter-card.png" + } + } +} diff --git a/apps/docs/extensions/block-node.mdx b/apps/docs/extensions/block-node.mdx new file mode 100644 index 0000000000..170dfd6437 --- /dev/null +++ b/apps/docs/extensions/block-node.mdx @@ -0,0 +1,194 @@ +--- +title: BlockNode extension +sidebarTitle: "Block Node" +keywords: "BlockNode extension, superdoc BlockNode, word BlockNode, document BlockNode, docx BlockNode" +--- + +import Description from '/snippets/extensions/block-node.mdx' + + + +## Commands + +### `replaceBlockNodeById` + +Replace a block node by its ID with new content + + +The replacement node should have the same type as the original + + +**Example:** + +```javascript +const newParagraph = editor.schema.nodes.paragraph.create({}, editor.schema.text('New content')) +editor.commands.replaceBlockNodeById('block-123', newParagraph) +``` + +**Parameters:** + + + The sdBlockId of the node to replace + + + The replacement ProseMirror node + + +### `deleteBlockNodeById` + +Delete a block node by its ID + + +Completely removes the node from the document + + +**Example:** + +```javascript +editor.commands.deleteBlockNodeById('block-123') +``` + +**Parameters:** + + + The sdBlockId of the node to delete + + +### `updateBlockNodeAttributes` + +Update attributes of a block node by its ID + + +Merges new attributes with existing ones + + +**Example:** + +```javascript +editor.commands.updateBlockNodeAttributes('block-123', { textAlign: 'center' }) +``` + +**Parameters:** + + + The sdBlockId of the node to update + + + Attributes to update + + +## Helpers + +### `getBlockNodes` + +Get all block nodes in the document + +**Example:** + +```javascript +const blocks = editor.helpers.blockNode.getBlockNodes() +console.log(`Found ${blocks.length} block nodes`) +``` + +**Returns:** + + + See [BlockNodeInfo](#blocknodeinfo) type definition + + +### `getBlockNodeById` + +Get a specific block node by its ID + +**Example:** + +```javascript +const block = editor.helpers.blockNode.getBlockNodeById('block-123') +if (block.length) console.log('Found:', block[0].node.type.name) +``` + +**Parameters:** + + + The sdBlockId to search for + + +**Returns:** + + + See [BlockNodeInfo](#blocknodeinfo) type definition + + +### `getBlockNodesByType` + +Get all block nodes of a specific type + +**Example:** + +```javascript +const paragraphs = editor.helpers.blockNode.getBlockNodesByType('paragraph') +const headings = editor.helpers.blockNode.getBlockNodesByType('heading') +``` + +**Parameters:** + + + The node type name (e.g., 'paragraph', 'heading') + + +**Returns:** + + + See [BlockNodeInfo](#blocknodeinfo) type definition + + +### `getBlockNodesInRange` + +Get all block nodes within a position range + +**Example:** + +```javascript +const selection = editor.state.selection +const blocksInSelection = editor.helpers.blockNode.getBlockNodesInRange( + selection.from, + selection.to +) +``` + +**Parameters:** + + + Start position + + + End position + + +**Returns:** + + + See [BlockNodeInfo](#blocknodeinfo) type definition + + +## Types + +### `BlockNodeInfo` + +Block node information object + + + + The block node + + + Position in the document + + + + +## 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 new file mode 100644 index 0000000000..333e3ee63e --- /dev/null +++ b/apps/docs/extensions/bold.mdx @@ -0,0 +1,39 @@ +--- +title: Bold extension +sidebarTitle: "Bold" +keywords: "Bold extension, superdoc Bold, word Bold, document Bold, docx Bold" +--- + +import Description from '/snippets/extensions/bold.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for the strong element + + +## Attributes + +Node attributes that can be set and retrieved: + + + Bold weight value ('0' renders as normal) + + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleBold() | `⌘/Ctrl-b` | Toggle bold formatting | +| toggleBold() | `⌘/Ctrl-B` | Toggle bold formatting (uppercase) | + + +## 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 new file mode 100644 index 0000000000..7cabcb11ae --- /dev/null +++ b/apps/docs/extensions/bullet-list.mdx @@ -0,0 +1,82 @@ +--- +title: BulletList extension +sidebarTitle: "Bullet List" +keywords: "BulletList extension, superdoc BulletList, word BulletList, document BulletList, docx BulletList" +--- + +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 + + +## Commands + +### `toggleBulletList` + +Toggle a bullet list at 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 + +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleBulletList() | `⌘/Ctrl-Shift-8` | Toggle bullet list | + + +## 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 new file mode 100644 index 0000000000..6e6e61a65e --- /dev/null +++ b/apps/docs/extensions/color.mdx @@ -0,0 +1,75 @@ +--- +title: Color extension +sidebarTitle: "Color" +keywords: "Color extension, superdoc Color, word Color, document Color, docx Color" +--- + +import Description from '/snippets/extensions/color.mdx' + + + +## Options + +Configure the extension behavior: + + + Mark types to add color support to + + +## Attributes + +Node attributes that can be set and retrieved: + + + Text color value + + +## Commands + +### `setColor` + +Set text color + + +Preserves other text styling attributes + + +**Example:** + +```javascript +// Set to red using hex +editor.commands.setColor('#ff0000') +``` + +**Parameters:** + + + Color value to apply + + +### `unsetColor` + +Remove text color + + +Removes color while preserving other text styles + + +**Example:** + +```javascript +editor.commands.unsetColor() +``` + +## Types + +### `ColorValue` + +Accepts hex colors (#ff0000), rgb(255,0,0), or named colors (red) + + +## 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 new file mode 100644 index 0000000000..24c9c97eab --- /dev/null +++ b/apps/docs/extensions/comments.mdx @@ -0,0 +1,81 @@ +--- +title: Comments Extension +sidebarTitle: Comments +--- + +The Comments extension enables Word-style commenting with threads, replies, and resolution. + +## Usage + +Comments work through the module configuration: + +```javascript +modules: { + comments: { + readOnly: false, + allowResolve: true + } +} +``` + +## Commands + +```javascript +// Add comment at selection +editor.commands.insertComment({ + content: 'Please review' +}); + +// Work with comments +editor.commands.replyToComment(commentId, { content: 'Done' }); +editor.commands.resolveComment(commentId); +editor.commands.deleteComment(commentId); + +// Navigate +editor.commands.goToNextComment(); +editor.commands.goToPreviousComment(); +``` + +## Events + +```javascript +superdoc.on('commentsUpdate', ({ type, comment }) => { + switch(type) { + case 'add': // Comment created + case 'update': // Comment edited + case 'deleted': // Comment removed + case 'resolved': // Comment resolved + } +}); +``` + +## Working with comment data + +```javascript +// Access all comments +const comments = editor.storage.comments.items; + +// Filter comments +const active = comments.filter(c => !c.resolved); +const byUser = comments.filter(c => c.user.email === email); +``` + +## Export behavior + +Comments export to DOCX as native Word comments: + +```javascript +// Include comments +await superdoc.export({ commentsType: 'external' }); + +// Clean export +await superdoc.export({ commentsType: 'clean' }); +``` + +## Styling + +```css +.comment-mark { background: #fff3cd; } +.comment-mark.resolved { opacity: 0.6; } +.comment-mark.active { background: #ffd700; } +``` diff --git a/apps/docs/extensions/content-block.mdx b/apps/docs/extensions/content-block.mdx new file mode 100644 index 0000000000..1d2128efd9 --- /dev/null +++ b/apps/docs/extensions/content-block.mdx @@ -0,0 +1,114 @@ +--- +title: ContentBlock extension +sidebarTitle: "Content Block" +keywords: "ContentBlock extension, superdoc ContentBlock, word ContentBlock, document ContentBlock, docx ContentBlock" +--- + +import Description from '/snippets/extensions/content-block.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for the block element + + +## Attributes + +Node attributes that can be set and retrieved: + + + Whether this block is a horizontal rule + + + + Size and position of the content block + + + + Background color for the block + + +## Commands + +### `insertHorizontalRule` + +Insert a horizontal rule + + +Creates a visual separator between content sections + + +**Example:** + +```javascript +editor.commands.insertHorizontalRule() +``` + +### `insertContentBlock` + +Insert a content block + + +Used for spacing, dividers, and special inline content + + +**Example:** + +```javascript +// Insert a spacer block +editor.commands.insertContentBlock({ size: { height: 20 } }) +``` + +**Parameters:** + + + Block configuration + + +## Types + +### `ContentBlockSize` + +Size configuration for content blocks + + + + Top position in pixels + + + Left position in pixels + + + Width in pixels or percentage (e.g., "50%") + + + Height in pixels or percentage + + + +### `ContentBlockConfig` + +Content block configuration + + + + Whether this is a horizontal rule + + + Size and position configuration + + + Background color (hex, rgb, or named color) + + + + +## 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 new file mode 100644 index 0000000000..af7ae4382f --- /dev/null +++ b/apps/docs/extensions/creating-extensions.mdx @@ -0,0 +1,158 @@ +--- +title: Creating Extensions +sidebarTitle: Create Your Own +--- + +Create extensions to add custom features to SuperDoc. + +## Basic extension + +```javascript +import { Extensions } from '@harbour-enterprises/superdoc'; +const { Extension } = Extensions; + +const MyExtension = Extension.create({ + name: 'myExtension', + + addCommands() { + return { + myCommand: () => ({ commands }) => { + console.log('Command executed'); + return true; + } + }; + } +}); + +// Use it +editor.commands.myCommand(); +``` + +## Extension types + +### Node extension +For document elements: + +```javascript +import { Extensions } from '@harbour-enterprises/superdoc'; + +const { Node } = Extensions; +const CustomBlock = Node.create({ + name: 'customBlock', + group: 'block', + content: 'inline*', + + parseHTML() { + return [{ tag: 'div[data-custom]' }]; + }, + + renderHTML({ HTMLAttributes }) { + return ['div', { 'data-custom': '' }, 0]; + } +}); +``` + +### Mark extension +For inline formatting: + +```javascript +import { Extensions } from '@harbour-enterprises/superdoc'; + +const { Mark } = Extensions; +const Highlight = Mark.create({ + name: 'highlight', + + addCommands() { + return { + toggleHighlight: () => ({ commands }) => { + return commands.toggleMark(this.name); + } + }; + } +}); +``` + +## Adding features + +### Commands +```javascript +addCommands() { + return { + simpleCommand: () => ({ commands }) => { + return commands.insertContent('Hello'); + }, + + complexCommand: (text) => ({ state, dispatch }) => { + dispatch(state.tr.insertText(text)); + return true; + } + }; +} +``` + +### Keyboard shortcuts +```javascript +addKeyboardShortcuts() { + return { + 'Mod-Shift-h': () => this.editor.commands.toggleHighlight() + }; +} +``` + +### ProseMirror plugins + +Your extension can also define ProseMirror plugins which will let you perform more advanced things, such as listening to browser events attached to a node. +```javascript +import { Plugin, PluginKey } from 'prosemirror-state'; + +// ... + +addPmPlugins() { + return [ + new Plugin({ + key: new PluginKey('myPlugin'), + props: { + handleClickOn: (view, pos, node, nodePos, event, direct) => { + console.log("Node was clicked!"); + } + }, + }) + ]; +} +``` +You can read more about ProseMirror's plugin system [here](https://prosemirror.net/docs/ref/#state.Plugin_System). + +### Configuration +```javascript +const ConfigurableExt = Extension.create({ + addOptions() { + return { + color: '#0000FF', + enabled: true + }; + }, + + addCommands() { + return { + applyColor: () => () => { + // Use this.options.color + } + }; + } +}); + +// Configure when using +ConfigurableExt.configure({ color: '#FF0000' }); +``` + +## Using your extension + +```javascript +new SuperDoc({ + selector: '#editor', + document: 'document.docx', + editorExtensions: [ + MyExtension, + ] +}); +``` diff --git a/apps/docs/extensions/custom-selection.mdx b/apps/docs/extensions/custom-selection.mdx new file mode 100644 index 0000000000..19b5748656 --- /dev/null +++ b/apps/docs/extensions/custom-selection.mdx @@ -0,0 +1,56 @@ +--- +title: CustomSelection extension +sidebarTitle: "Custom Selection" +keywords: "CustomSelection extension, superdoc CustomSelection, word CustomSelection, document CustomSelection, docx CustomSelection" +--- + +import Description from '/snippets/extensions/custom-selection.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 + +## Types + +### `SelectionState` + +Selection state + + + + Whether editor is focused + + + Stored selection + + + Whether to show selection decoration + + + Whether to skip clearing selection on next focus + + + + +## 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 new file mode 100644 index 0000000000..9553b375e2 --- /dev/null +++ b/apps/docs/extensions/document-section.mdx @@ -0,0 +1,295 @@ +--- +title: Document Section Extension +sidebarTitle: Document Section +--- + +Encapsulate and manage discrete parts of documents. Legal clauses stay locked while sales updates pricing. + +## Installation + +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 +}); +``` + +## Commands + +All commands available on `editor.commands`: + +### Section Creation + +```javascript +editor.commands.createDocumentSection({ + id: 'legal-1', + title: 'Terms & Conditions', + description: 'Legal terms', + isLocked: true, + html: '

Content...

' +}) +``` + +### Section Manipulation + +```javascript +editor.commands.removeSectionAtSelection() +editor.commands.removeSectionById('legal-1') +editor.commands.lockSectionById('legal-1') +editor.commands.updateSectionById({ + id: 'legal-1', + html: '

Updated...

', + attrs: { title: 'New Title' } +}) +``` + +## Helper Functions + +Import helpers: + +```javascript +import { SectionHelpers } from '@harbour-enterprises/superdoc'; +``` + +### Available Helpers + +```javascript +// Get all sections +const sections = SectionHelpers.getAllSections(editor); + +// Export sections +const html = SectionHelpers.exportSectionsToHTML(editor); +const json = SectionHelpers.exportSectionsToJSON(editor); + +// Create linked editor +const childEditor = SectionHelpers.getLinkedSectionEditor( + 'section-id', + { element: '#editor' }, + parentEditor +); +``` + +## Attributes + +Section nodes have these attributes: + +| Attribute | Type | Default | Description | +|-----------|------|---------|-------------| +| `id` | string/number | auto | Unique identifier | +| `title` | string | '' | Section label (w:alias in Word) | +| `description` | string | '' | Metadata (w:tag in Word) | +| `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 + +Sections export as Word content controls: + +```xml + + + + + + + + + + +``` + +## Common Patterns + +### Contract Structure + +```javascript +const contractSections = [ + { id: 'parties', title: '1. Parties', isLocked: false }, + { id: 'terms', title: '2. Terms', isLocked: true }, + { id: 'pricing', title: '3. Pricing', isLocked: false }, + { id: 'signatures', title: '4. Signatures', isLocked: true } +]; + +contractSections.forEach(section => { + editor.commands.createDocumentSection({ + ...section, + html: loadTemplate(section.id) + }); +}); +``` + +### Role-Based Locking + +```javascript +function applyRolePermissions(userRole) { + const sections = SectionHelpers.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 diff --git a/apps/docs/extensions/document.mdx b/apps/docs/extensions/document.mdx new file mode 100644 index 0000000000..5dee7ac4ac --- /dev/null +++ b/apps/docs/extensions/document.mdx @@ -0,0 +1,48 @@ +--- +title: Document extension +sidebarTitle: "Document" +keywords: "Document extension, superdoc Document, word Document, document Document, docx Document" +--- + +import Description from '/snippets/extensions/document.mdx' + + + +## Commands + +### `getDocumentStats` + +Get document statistics + + +Returns word count, character count, and paragraph count + + +**Example:** + +```javascript +// Get word and character count +const stats = editor.commands.getDocumentStats() +console.log(`${stats.words} words, ${stats.characters} characters`) +``` + +### `clearDocument` + +Clear entire document + + +Replaces all content with an empty paragraph + + +**Example:** + +```javascript +editor.commands.clearDocument() +``` + + +## 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 new file mode 100644 index 0000000000..4e473db844 --- /dev/null +++ b/apps/docs/extensions/dropcursor.mdx @@ -0,0 +1,50 @@ +--- +title: DropCursor extension +sidebarTitle: "Drop Cursor" +keywords: "DropCursor extension, superdoc DropCursor, word DropCursor, document DropCursor, docx DropCursor" +--- + +import Description from '/snippets/extensions/dropcursor.mdx' + + + +## Options + +Configure the extension behavior: + + + CSS color for the drop cursor indicator + + + + Width of the drop cursor line in pixels + + + + Optional CSS class to apply to the drop cursor element + + +**Example:** + +```javascript +// Customize drop cursor appearance +const ConfiguredDropCursor = DropCursor.configure({ + color: '#3b82f6', + width: 3, + class: 'custom-drop-cursor' +}); + +// Use in SuperDoc +new SuperDoc({ + selector: '#editor', + document: 'document.docx', + editorExtensions: [ConfiguredDropCursor] +}); +``` + + +## 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 new file mode 100644 index 0000000000..9378a1a42c --- /dev/null +++ b/apps/docs/extensions/field-annotation.mdx @@ -0,0 +1,1093 @@ +--- +title: Field Annotation +description: "Interactive form fields for documents. It can be used when variable content is needed inside the document. Supports text, signature, image, checkbox, link, and HTML field types." +--- + +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). + +## Configuration + + + Handle drops outside editor viewport + + + + CSS class for field styling + + + + Default field background color + + + + Maximum annotations per document + + + + +## Usage + +**Basic Setup:** + +```javascript +import { FieldAnnotationPlugin } from '@superdoc/field-annotation'; + +const plugin = FieldAnnotationPlugin({ + editor: myEditor, + handleDropOutside: true +}); +``` + +**Form Template Workflow:** + +```javascript +// 1. Create form fields +const fields = [ + { id: 'name', label: 'Full Name', type: 'text' }, + { id: 'date', label: 'Date', type: 'text' }, + { id: 'signature', label: 'Sign Here', type: 'signature' } +]; + +// 2. Insert fields into document +fields.forEach((field, i) => { + editor.commands.addFieldAnnotation(i * 100, { + fieldId: field.id, + displayLabel: field.label, + type: field.type + }); +}); + +// 3. Handle user interactions +editor.on('fieldAnnotationClicked', ({ node }) => { + openFieldEditor(node.attrs.fieldId); +}); + +// 4. Fill and export +editor.annotate([ + { input_id: 'name', input_value: 'John Doe' }, + { input_id: 'date', input_value: '2024-01-15' } +]); +``` + +## Commands + +### Find & Search + +#### `findFieldAnnotations` + +Find field annotations matching a predicate function + +Added in v0.10.3 + +```javascript +// Find all signature fields +const signatureFields = findFieldAnnotations( + node => node.attrs.type === 'signature', + state +); +``` + +```javascript +// Find fields with specific color +const redFields = findFieldAnnotations( + node => node.attrs.fieldColor === '#FF0000', + state +); +``` + +**Parameters:** + + + Function to test each annotation node + + + + ProseMirror editor state + + + + +**Returns:** + + + Matching field annotations + + + pos of each object + + + node of each object + + + + +#### `findFieldAnnotationsBetween` + +Find all field annotations between two positions + +```javascript +// Find fields in selection +const { from, to } = state.selection; +const selectedFields = findFieldAnnotationsBetween(from, to, state.doc); +``` + +```javascript +// Find fields in specific range +const rangeFields = findFieldAnnotationsBetween(100, 500, state.doc); +console.log(`Found ${rangeFields.length} fields in range`); +``` + +**Parameters:** + + + Start position + + + + End position + + + + ProseMirror document node + + + + +**Returns:** + + + Field annotations in range + + + pos of each object + + + node of each object + + + + +#### `findFieldAnnotationsByFieldId` + +Find field annotations by field ID(s) + +```javascript +// Find single field +const fields = findFieldAnnotationsByFieldId('field-123', state); +``` + +```javascript +// Find multiple fields +const fields = findFieldAnnotationsByFieldId(['field-1', 'field-2'], state); +fields.forEach(({ pos, node }) => { + console.log(`Found ${node.attrs.fieldId} at position ${pos}`); +}); +``` + +**Parameters:** + + + Single field ID or array of field IDs + + + + ProseMirror editor state + + + + +**Returns:** + + + Matching field annotations + + + pos of each object + + + node of each object + + + + +#### `findFirstFieldAnnotationByFieldId` + +Find the first field annotation matching a field ID + +Added in v0.10.2 + +```javascript +const firstField = findFirstFieldAnnotationByFieldId('field-123', state); +if (firstField) { + console.log(`First occurrence at position ${firstField.pos}`); +} +``` + +**Parameters:** + + + Field ID to search for + + + + ProseMirror editor state + + + + +**Returns:** + + + First matching annotation or null + + +#### `findHeaderFooterAnnotationsByFieldId` + +Find field annotations in headers and footers by field ID or array of field IDs. + +Added in v0.11.2 + +```javascript +const headerFooterAnnotations = findHeaderFooterAnnotationsByFieldId('field-123', editor, activeSectionEditor); +headerFooterAnnotations.forEach(({ node, pos }) => { + console.log(`Field ${node.attrs.fieldId} at position ${pos}`); +}); +``` + +**Parameters:** + + + The field ID or array of field IDs + + + + The main editor instance + + + + The currently active section editor + + + + +**Returns:** + + + Array of field annotations with their positions + + + node of each object + + + pos of each object + + + + +#### `getAllFieldAnnotations` + +Get all field annotations in the document + +```javascript +import { getAllFieldAnnotations } from './fieldAnnotationHelpers'; + +const annotations = getAllFieldAnnotations(editor.state); +console.log(`Document contains ${annotations.length} field annotations`); + +annotations.forEach(({ pos, node }) => { + console.log(`Field ${node.attrs.fieldId} at position ${pos}`); +}); +``` + +**Parameters:** + + + ProseMirror editor state + + + + +**Returns:** + + + Array of field annotations with positions + + + pos of each object + + + node of each object + + + + +#### `getAllFieldAnnotationsWithRect` + +Get all field annotations with their bounding rectangles + +Added in v0.11.0 + +```javascript +const annotationsWithRects = getAllFieldAnnotationsWithRect(view, state); +annotationsWithRects.forEach(({ node, rect }) => { + console.log(`Field ${node.attrs.fieldId} at ${rect.left}, ${rect.top}`); +}); +``` + +**Parameters:** + + + ProseMirror editor view + + + + ProseMirror editor state + + + + +**Returns:** + + + Annotations with positions and rectangles + + + pos of each object + + + node of each object + + + rect of each object + + + + +### Delete & Remove + +#### `findRemovedFieldAnnotations` + +Find field annotation nodes that were removed in a transaction + +Added in v0.11.2 + +```javascript +const removedFields = findRemovedFieldAnnotations(transaction); +removedFields.forEach(({ node, pos }) => { + console.log(`Field ${node.attrs.fieldId} at position ${pos}`); +}); +``` + +**Parameters:** + + + ProseMirror transaction to analyze + + + + +**Returns:** + + + Array of removed field annotation nodes with their positions + + + node of each object + + + pos of each object + + + + +#### `deleteFieldAnnotations` + +Delete field annotations by field ID + +```javascript +// Delete single field annotation +editor.commands.deleteFieldAnnotations('field-123') +``` + +```javascript +// Delete multiple field annotations +editor.commands.deleteFieldAnnotations(['field-1', 'field-2']) +``` + +**Parameters:** + + + Field ID or array of field IDs to delete + + + + +**Returns:** `boolean` Command success status + +#### `deleteFieldAnnotationsByNode` + +Delete field annotations by node references + +```javascript +const annotations = editor.helpers.fieldAnnotation.getAllFieldAnnotations(); +editor.commands.deleteFieldAnnotationsByNode(annotations.slice(0, 2)); +``` + +**Parameters:** + + + Array of annotation objects to delete + + + + +**Returns:** `boolean` Command success status + +#### `deleteFieldAnnotation` + +Delete a single field annotation + +```javascript +const annotation = editor.helpers.fieldAnnotation.findFieldAnnotationsByFieldId('field-123')[0]; +editor.commands.deleteFieldAnnotation(annotation); +``` + +**Parameters:** + + + Annotation object to delete + + + + +**Returns:** `boolean` Command success status + +#### `sliceFieldAnnotations` + +Delete a portion of annotations associated with a field + +```javascript +// Remove annotations starting from index 6 +editor.commands.sliceFieldAnnotations('field-123', 5) +``` + +```javascript +// Remove from multiple fields +editor.commands.sliceFieldAnnotations(['field-1', 'field-2'], 5) +``` + +**Parameters:** + + + The field ID or array of field IDs + + + + Index at which to end extraction + + + + +**Returns:** `boolean` Command success status + +### Create & Add + +#### `addFieldAnnotation` + +Add field annotation at specified position + +```javascript +editor.commands.addFieldAnnotation(10, { + fieldId: 'field-123', + displayLabel: 'Enter your name', + fieldType: 'TEXTINPUT', + fieldColor: '#980043' +}) +``` + +**Parameters:** + + + Document position to insert annotation + + + + Field annotation attributes + + + Unique field identifier + + + Text to display in annotation + + + Type of field (TEXTINPUT, CHECKBOX, etc.) + + + Background color for annotation + + + Annotation type (text, image, signature, etc.) + + + + + + Whether to focus editor after insertion + + + + +**Returns:** `boolean` Command success status + +#### `addFieldAnnotationAtSelection` + +Add field annotation at current selection position + +```javascript +editor.commands.addFieldAnnotationAtSelection({ + fieldId: 'field-456', + displayLabel: 'Signature here' +}, true) +``` + +**Parameters:** + + + Field annotation attributes + + + + Whether to focus editor after insertion + + + + +**Returns:** `boolean` Command success status + +### Update & Edit + +#### `replaceWithFieldAnnotation` + +Replace text ranges with field annotations + +```javascript +editor.commands.replaceWithFieldAnnotation([{ + from: 20, + to: 45, + attrs: { + fieldId: 'field-789', + fieldType: 'TEXTINPUT', + fieldColor: '#980043' + } +}]) +``` + +**Parameters:** + + + Array of field replacement objects + + + + Options object + + + Start position + + + End position + + + Field annotation attributes + + + + + + +**Returns:** `boolean` Command success status + +#### `replaceFieldAnnotationsWithLabelInSelection` + +Replace field annotations with text labels in current selection + +Added in v0.11.0 + +```javascript +// Replace all annotations in selection with their labels +editor.commands.replaceFieldAnnotationsWithLabelInSelection() +``` + +**Parameters:** + + + Additional options + + + + +**Returns:** `boolean` Command success status + +#### `replaceFieldAnnotationsWithLabel` + +Replace field annotations with text labels + +Added in v0.11.0 + +```javascript +// Replace specific fields with labels +editor.commands.replaceFieldAnnotationsWithLabel(['field-1', 'field-2']) +``` + +```javascript +// Replace only text annotations in selection +editor.commands.replaceFieldAnnotationsWithLabel(null, { + isInSelection: true, + types: ['text'] +}) +``` + +**Parameters:** + + + Field ID(s) to replace + + + + Replace options + + + Replace only in selection + + + Add operation to undo history + + + Annotation types to replace + + + + + + +**Returns:** `boolean` Command success status + +#### `resetFieldAnnotations` + +Reset all field annotations to their default values + +```javascript +// Reset all annotations in document +editor.commands.resetFieldAnnotations() +``` + +**Returns:** `boolean` Command success status + +#### `updateFieldAnnotations` + +Update field annotations by field ID + +```javascript +// Update single field +editor.commands.updateFieldAnnotations('field-123', { + displayLabel: 'Updated label', + fieldColor: '#FF0000' +}) +``` + +```javascript +// Update multiple fields +editor.commands.updateFieldAnnotations(['field-1', 'field-2'], { + hidden: true +}) +``` + +**Parameters:** + + + Field ID or array of field IDs + + + + Attributes to update + + + New display label + + + New field color + + + Hide/show annotation + + + + + + +**Returns:** `boolean` Command success status + +#### `updateFieldAnnotation` + +Update a specific field annotation instance + +```javascript +// Update specific annotation instance +const annotation = editor.helpers.fieldAnnotation.findFirstFieldAnnotationByFieldId('field-123', state); +editor.commands.updateFieldAnnotation(annotation, { + displayLabel: 'New label' +}) +``` + +**Parameters:** + + + Annotation object with pos and node + + + + Attributes to update + + + + +**Returns:** `boolean` Command success status + +#### `updateFieldAnnotationsAttributes` + +Update the attributes of annotations + +```javascript +const annotations = editor.helpers.fieldAnnotation.getAllFieldAnnotations(); +editor.commands.updateFieldAnnotationsAttributes(annotations, { + fieldColor: '#FF0000', + hidden: false +}); +``` + +**Parameters:** + + + Array of annotations to update + + + + Attributes to update + + + + +**Returns:** `boolean` Command success status + +#### `setFieldAnnotationsHiddenByCondition` + +Hide field annotations based on a condition + +```javascript +// Hide specific field IDs +editor.commands.setFieldAnnotationsHiddenByCondition(node => { + const targetIds = ['field-1', 'field-2', 'field-3']; + return targetIds.includes(node.attrs.fieldId); +}) +``` + +```javascript +// Hide signature fields and show others +editor.commands.setFieldAnnotationsHiddenByCondition( + node => node.attrs.type === 'signature', + true +) +``` + +**Parameters:** + + + Function to test each annotation + + + + Whether to show non-matching annotations + + + + +**Returns:** `boolean` Command success status + +#### `unsetFieldAnnotationsHidden` + +Show all hidden field annotations + +```javascript +// Make all annotations visible +editor.commands.unsetFieldAnnotationsHidden() +``` + +**Returns:** `boolean` Command success status + +#### `setFieldAnnotationsVisibility` + +Set visibility for all field annotations + +```javascript +// Make all annotations visible +editor.commands.setFieldAnnotationsVisibility('visible') +``` + +```javascript +// Hide all annotations (preserves layout) +editor.commands.setFieldAnnotationsVisibility('hidden') +``` + +**Parameters:** + + + Visibility value ('visible' or 'hidden') + + + + +**Returns:** `boolean` Command success status + +#### `setFieldAnnotationsHighlighted` + +Set highlighted status for annotations matching predicate + +```javascript +// Highlight specific field IDs +editor.commands.setFieldAnnotationsHighlighted((node) => { + const targetIds = ['field-1', 'field-2', 'field-3']; + return targetIds.includes(node.attrs.fieldId); +}, true) +``` + +```javascript +// Remove highlighting from all annotations +editor.commands.setFieldAnnotationsHighlighted(() => true, false) +``` + +**Parameters:** + + + Function to test each annotation node + + + + Whether to highlight matching annotations + + + + +**Returns:** `boolean` Command success status + +#### `toggleFieldAnnotationsFormat` + +Toggle formatting for field annotations in selection + +```javascript +// Toggle bold formatting on selected annotations +editor.commands.toggleFieldAnnotationsFormat('bold'); +``` + +```javascript +// Toggle italic and update selection +editor.commands.toggleFieldAnnotationsFormat('italic', true); +``` + +**Parameters:** + + + Format name (bold, italic, underline) + + + + Whether to set selection after toggle + + + + +**Returns:** `boolean` Command success status + +#### `setFieldAnnotationsFontFamily` + +Set font family for field annotations in current selection + +```javascript +editor.commands.setFieldAnnotationsFontFamily('Arial', true) +``` + +**Parameters:** + + + Font family name to apply + + + + Whether to set node selection after update + + + + +**Returns:** `boolean` Command success status + +#### `setFieldAnnotationsFontSize` + +Set font size for field annotations in current selection + +```javascript +editor.commands.setFieldAnnotationsFontSize('14pt') +``` + +**Parameters:** + + + Font size value (e.g., '12pt', '14px') + + + + Whether to set node selection after update + + + + +**Returns:** `boolean` Command success status + +#### `setFieldAnnotationsTextHighlight` + +Set text highlight color for field annotations in current selection + +```javascript +editor.commands.setFieldAnnotationsTextHighlight('#ffff00') +``` + +**Parameters:** + + + Highlight color value (e.g., '#ffff00', 'yellow') + + + + Whether to set node selection after update + + + + +**Returns:** `boolean` Command success status + +#### `setFieldAnnotationsTextColor` + +Set text color for field annotations in current selection + +```javascript +editor.commands.setFieldAnnotationsTextColor('#0066cc') +``` + +**Parameters:** + + + Text color value (e.g., '#000000', 'black') + + + + Whether to set node selection after update + + + + +**Returns:** `boolean` Command success status + +## Helpers + +#### `transactionDeletedAnything` + +Check if a transaction contains any deletion operations + +**Parameters:** + + + ProseMirror transaction to check + + + + +**Returns:** `boolean` True if transaction contains deletions + +#### `trackFieldAnnotationsDeletion` + +Track field annotation deletions in a transaction and emit events + +Added in v0.11.2 + +```javascript +// Listen for field deletions +editor.on('fieldAnnotationDeleted', ({ removedNodes }) => { + removedNodes.forEach(({ node }) => { + console.log(`Field ${node.attrs.fieldId} was deleted`); + // Clean up external references + removeFieldFromDatabase(node.attrs.fieldId); + }); +}); +``` + +**Parameters:** + + + SuperDoc editor instance + + + + ProseMirror transaction + + + + +**Returns:** `void` + +#### `handleDropOutside` + +Handle field annotation drops outside editor boundaries + +**Parameters:** + + + Drop handling parameters + + + Serialized field data + + + SuperDoc editor instance + + + ProseMirror editor view + + + Browser drag event + + + + + + +## Events + +#### `fieldAnnotationClicked` + +Field annotation clicked event + +**Event Data:** + + +- `node` (Node) - The clicked annotation node +- `nodePos` (number) - Position of the node in the document + +#### `fieldAnnotationDropped` + +Field annotation dropped event + +**Event Data:** + + +- `sourceField` (object) - The dropped field attributes \ No newline at end of file diff --git a/apps/docs/extensions/font-family.mdx b/apps/docs/extensions/font-family.mdx new file mode 100644 index 0000000000..46a2765785 --- /dev/null +++ b/apps/docs/extensions/font-family.mdx @@ -0,0 +1,75 @@ +--- +title: FontFamily extension +sidebarTitle: "Font Family" +keywords: "FontFamily extension, superdoc FontFamily, word FontFamily, document FontFamily, docx FontFamily" +--- + +import Description from '/snippets/extensions/font-family.mdx' + + + +## Options + +Configure the extension behavior: + + + Mark types to add font family support to + + +## Attributes + +Node attributes that can be set and retrieved: + + + Font family for text + + +## Commands + +### `setFontFamily` + +Set font family + + +Preserves other text styling attributes + + +**Example:** + +```javascript +// Set to Arial +editor.commands.setFontFamily('Arial') +``` + +**Parameters:** + + + Font family to apply + + +### `unsetFontFamily` + +Remove font family + + +Reverts to default document font + + +**Example:** + +```javascript +editor.commands.unsetFontFamily() +``` + +## Types + +### `FontFamilyValue` + +CSS font-family string (e.g., 'Arial', 'Times New Roman', 'sans-serif') + + +## 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 new file mode 100644 index 0000000000..3166eca56e --- /dev/null +++ b/apps/docs/extensions/font-size.mdx @@ -0,0 +1,99 @@ +--- +title: FontSize extension +sidebarTitle: "Font Size" +keywords: "FontSize extension, superdoc FontSize, word FontSize, document FontSize, docx FontSize" +--- + +import Description from '/snippets/extensions/font-size.mdx' + + + +## Options + +Configure the extension behavior: + + + Node/mark types to add font size support to + + + + Default size configuration + + +## Attributes + +Node attributes that can be set and retrieved: + + + Font size with unit + + +## Commands + +### `setFontSize` + +Set font size + + +Automatically clamps to min/max values + + +**Example:** + +```javascript +editor.commands.setFontSize('14pt') +editor.commands.setFontSize('18px') +editor.commands.setFontSize(16) +``` + +**Parameters:** + + + Size to apply (with optional unit) + + +### `unsetFontSize` + +Remove font size + + +Reverts to default document size + + +**Example:** + +```javascript +editor.commands.unsetFontSize() +``` + +## Types + +### `FontSizeDefaults` + +Font size configuration + + + + Default font size value + + + Default unit (pt, px, em, rem) + + + Minimum allowed size + + + Maximum allowed size + + + +### `FontSizeValue` + +Size with optional unit (e.g., '12pt', '16px', 14) + + +## 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 new file mode 100644 index 0000000000..273830b320 --- /dev/null +++ b/apps/docs/extensions/format-commands.mdx @@ -0,0 +1,95 @@ +--- +title: FormatCommands extension +sidebarTitle: "Format Commands" +keywords: "FormatCommands extension, superdoc FormatCommands, word FormatCommands, document FormatCommands, docx FormatCommands" +--- + +import Description from '/snippets/extensions/format-commands.mdx' + + + +## Commands + +### `clearFormat` + +Clear all formatting (nodes and marks) + + +Removes all marks and resets nodes to default paragraph + + +**Example:** + +```javascript +editor.commands.clearFormat() +``` + +### `clearMarksFormat` + +Clear only mark formatting + + +Removes bold, italic, underline, colors, etc. but preserves block structure + + +**Example:** + +```javascript +editor.commands.clearMarksFormat() +``` + +### `clearNodesFormat` + +Clear only node formatting + + +Converts headings, lists, etc. to paragraphs but preserves text marks + + +**Example:** + +```javascript +editor.commands.clearNodesFormat() +``` + +### `copyFormat` + +Copy format from selection or apply copied format + + +Works like format painter - first click copies, second click applies + + +**Example:** + +```javascript +editor.commands.copyFormat() +``` + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| clearFormat() | `⌘/Ctrl-Alt-c` | Clear all formatting | + +## Types + +### `StoredStyle` + +Stored format style + + + + Mark name + + + Mark attributes + + + + +## 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 new file mode 100644 index 0000000000..fba8ad58cd --- /dev/null +++ b/apps/docs/extensions/gapcursor.mdx @@ -0,0 +1,16 @@ +--- +title: Gapcursor extension +sidebarTitle: "Gap Cursor" +keywords: "Gapcursor extension, superdoc Gapcursor, word Gapcursor, document Gapcursor, docx Gapcursor" +--- + +import Description from '/snippets/extensions/gapcursor.mdx' + + + + +## 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 new file mode 100644 index 0000000000..b450910f10 --- /dev/null +++ b/apps/docs/extensions/heading.mdx @@ -0,0 +1,86 @@ +--- +title: Heading extension +sidebarTitle: "Heading" +keywords: "Heading extension, superdoc Heading, word Heading, document Heading, docx Heading" +--- + +import Description from '/snippets/extensions/heading.mdx' + + + +## Options + +Configure the extension behavior: + + + Supported heading levels + + +## Attributes + +Node attributes that can be set and retrieved: + + + Heading level (1-6) + + +## Commands + +### `setHeading` + +Set a heading with specified level + + +Converts current block to heading + + +**Example:** + +```javascript +editor.commands.setHeading({ level: 2 }) +``` + +**Parameters:** + + + Heading attributes including level + + +### `toggleHeading` + +Toggle between heading and paragraph + + +Switches between heading and paragraph for the same level + + +**Example:** + +```javascript +editor.commands.toggleHeading({ level: 1 }) +editor.commands.toggleHeading({ level: 3 }) +``` + +**Parameters:** + + + Heading attributes including level + + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleHeading() | `⌘/Ctrl-Alt-1` | Toggle heading level 1 | +| toggleHeading() | `⌘/Ctrl-Alt-2` | Toggle heading level 2 | +| toggleHeading() | `⌘/Ctrl-Alt-3` | Toggle heading level 3 | +| toggleHeading() | `⌘/Ctrl-Alt-4` | Toggle heading level 4 | +| toggleHeading() | `⌘/Ctrl-Alt-5` | Toggle heading level 5 | +| toggleHeading() | `⌘/Ctrl-Alt-6` | Toggle heading level 6 | + + +## 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 new file mode 100644 index 0000000000..2932ea699e --- /dev/null +++ b/apps/docs/extensions/highlight.mdx @@ -0,0 +1,77 @@ +--- +title: Highlight extension +sidebarTitle: "Highlight" +keywords: "Highlight extension, superdoc Highlight, word Highlight, document Highlight, docx Highlight" +--- + +import Description from '/snippets/extensions/highlight.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for highlight elements + + +## Attributes + +Node attributes that can be set and retrieved: + + + Background color (CSS color value) + + +## Commands + +### `setHighlight` + +Apply highlight with specified color + +**Example:** + +```javascript +editor.commands.setHighlight('#FFEB3B') +editor.commands.setHighlight('rgba(255, 235, 59, 0.5)') +``` + +**Parameters:** + + + CSS color value + + +### `unsetHighlight` + +Remove highlight formatting + +**Example:** + +```javascript +editor.commands.unsetHighlight() +``` + +### `toggleHighlight` + +Toggle highlight formatting + +**Example:** + +```javascript +editor.commands.toggleHighlight() +``` + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleHighlight() | `⌘/Ctrl-Shift-h` | Toggle highlighted formatting | + + +## 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 new file mode 100644 index 0000000000..b518ac60e5 --- /dev/null +++ b/apps/docs/extensions/history.mdx @@ -0,0 +1,66 @@ +--- +title: History extension +sidebarTitle: "History" +keywords: "History extension, superdoc History, word History, document History, docx History" +--- + +import Description from '/snippets/extensions/history.mdx' + + + +## Options + +Configure the extension behavior: + + + Maximum undo/redo steps to remember + + + + Milliseconds to wait before starting a new history group + + +## Commands + +### `undo` + +Undo the last action + + +Groups changes within the newGroupDelay window + + +**Example:** + +```javascript +editor.commands.undo() +``` + +### `redo` + +Redo the last undone action + + +Only available after an undo action + + +**Example:** + +```javascript +editor.commands.redo() +``` + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| undo() | `⌘/Ctrl-z` | Undo last action | +| redo() | `⌘/Ctrl-Shift-z` | Redo last action | +| redo() | `⌘/Ctrl-y` | Redo last action (alternative) | + + +## 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 new file mode 100644 index 0000000000..6deb90ef53 --- /dev/null +++ b/apps/docs/extensions/image.mdx @@ -0,0 +1,192 @@ +--- +title: Image extension +sidebarTitle: "Image" +keywords: "Image extension, superdoc Image, word Image, document Image, docx Image" +--- + +import Description from '/snippets/extensions/image.mdx' + + + +## Options + +Configure the extension behavior: + + + Allow base64 encoded images + + + + Default HTML attributes for image elements + + +## Attributes + +Node attributes that can be set and retrieved: + + + Image source URL or path + + + + Alternative text for accessibility + + + + Image title/tooltip text + + + + Image dimensions + + + + Width in pixels + + + + Height in pixels + + + + Image padding/margins + + + + Left padding in pixels + + + + Top padding in pixels + + + + Bottom padding in pixels + + + + Right padding in pixels + + + + Margin offset for anchored images + + + + Left/right margin offset + + + + Top margin offset + + + + Custom inline CSS styles + + +## Commands + +### `setImage` + +Insert an image at the current position + + +Supports URLs, relative paths, and base64 data URIs + + +**Example:** + +```javascript +editor.commands.setImage({ src: 'https://example.com/image.jpg' }) +editor.commands.setImage({ + src: 'data:image/png;base64,...', + alt: 'Company logo', + size: { width: 200 } +}) +``` + +**Parameters:** + + + Image insertion options + + +### `setWrapping` + +Set the wrapping mode and attributes for the selected image + +**Example:** + +```javascript +// No wrapping, behind document +editor.commands.setWrapping({ type: 'None', attrs: {behindDoc: true} }) + +// Square wrapping on both sides with distances +editor.commands.setWrapping({ + type: 'Square', + attrs: { + wrapText: 'bothSides', + distTop: 10, + distBottom: 10, + distLeft: 10, + distRight: 10 + } +}) + +// Tight wrapping with polygon +editor.commands.setWrapping({ + type: 'Tight', + attrs: { + polygon: [[0, 0], [100, 0], [100, 100], [0, 100]] + } +}) + +// Top and bottom wrapping +editor.commands.setWrapping({ + type: 'TopAndBottom', + attrs: { + distTop: 15, + distBottom: 15 + } +}) +``` + +**Parameters:** + + + Wrapping options + + +## Types + +### `ImageInsertOptions` + +Options for inserting an image + + + + Image source URL or data URI + + + Alternative text + + + Image title + + + Image dimensions + + + Width in pixels + + + Height in pixels + + + + +## 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 new file mode 100644 index 0000000000..32190997f9 --- /dev/null +++ b/apps/docs/extensions/italic.mdx @@ -0,0 +1,31 @@ +--- +title: Italic extension +sidebarTitle: "Italic" +keywords: "Italic extension, superdoc Italic, word Italic, document Italic, docx Italic" +--- + +import Description from '/snippets/extensions/italic.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for italic elements + + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleItalic() | `⌘/Ctrl-i` | Toggle italic formatting | +| toggleItalic() | `⌘/Ctrl-I` | Toggle italic formatting (uppercase) | + + +## 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 new file mode 100644 index 0000000000..caa56e5703 --- /dev/null +++ b/apps/docs/extensions/line-break.mdx @@ -0,0 +1,46 @@ +--- +title: LineBreak extension +sidebarTitle: "Line Break" +keywords: "LineBreak extension, superdoc LineBreak, word LineBreak, document LineBreak, docx LineBreak" +--- + +import Description from '/snippets/extensions/line-break.mdx' + + + +## Commands + +### `insertLineBreak` + +Insert a line break + + +Creates a soft break within the same paragraph + + +**Example:** + +```javascript +editor.commands.insertLineBreak() +``` + +### `insertPageBreak` + +Insert a page break + + +Forces content to start on a new page when printed + + +**Example:** + +```javascript +editor.commands.insertPageBreak() +``` + + +## 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 new file mode 100644 index 0000000000..3963f345ae --- /dev/null +++ b/apps/docs/extensions/line-height.mdx @@ -0,0 +1,84 @@ +--- +title: LineHeight extension +sidebarTitle: "Line Height" +keywords: "LineHeight extension, superdoc LineHeight, word LineHeight, document LineHeight, docx LineHeight" +--- + +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 + + +**Example:** + +```javascript +editor.commands.setLineHeight(1.5) +editor.commands.setLineHeight('24px') +editor.commands.setLineHeight(2) +``` + +**Parameters:** + + + Line height to apply + + +### `unsetLineHeight` + +Remove line height + + +Reverts to default line spacing + + +**Example:** + +```javascript +editor.commands.unsetLineHeight() +``` + +## Types + +### `LineHeightValue` + +Line height as number (1.5) or string with unit ('1.5em', '24px') + + +## 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 new file mode 100644 index 0000000000..dd6273c931 --- /dev/null +++ b/apps/docs/extensions/link.mdx @@ -0,0 +1,160 @@ +--- +title: Link extension +sidebarTitle: "Link" +keywords: "Link extension, superdoc Link, word Link, document Link, docx Link" +--- + +import Description from '/snippets/extensions/link.mdx' + + + +## Options + +Configure the extension behavior: + + + Allowed URL protocols + + + + HTML attributes for link elements + + + + Default link target + + + + Default rel attribute + + + + CSS class + + + + Title attribute + + +## Attributes + +Node attributes that can be set and retrieved: + + + URL or anchor reference + + + + Link target window + + + + Relationship attributes + + + + Display text for the link + + + + Anchor name for internal references + + + + Whether to add to viewed hyperlinks list + + + + Bookmark target name (ignored if rId and href specified) + + + + Location in target hyperlink + + + + Tooltip for the link + + +## Commands + +### `setLink` + +Create or update a link + + +Automatically adds underline formatting and trims whitespace from link boundaries + + +**Example:** + +```javascript +editor.commands.setLink({ href: 'https://example.com' }) +editor.commands.setLink({ + href: 'https://example.com', + text: 'Visit Example' +}) +``` + +**Parameters:** + + + Link configuration + + +### `unsetLink` + +Remove link and associated formatting + + +Also removes underline and text color + + +**Example:** + +```javascript +editor.commands.unsetLink() +``` + +### `toggleLink` + +Toggle link on selection + +**Example:** + +```javascript +editor.commands.toggleLink({ href: 'https://example.com' }) +editor.commands.toggleLink() +``` + +**Parameters:** + + + Link configuration + + +## Types + +### `TargetFrameOptions` + +Target frame options + +### `SetLinkOptions` + +Link options for setLink command + + + + URL for the link + + + Display text (uses selection if omitted) + + + + +## 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 new file mode 100644 index 0000000000..66b1da1336 --- /dev/null +++ b/apps/docs/extensions/linked-styles.mdx @@ -0,0 +1,193 @@ +--- +title: CustomSelection extension +sidebarTitle: "Custom Selection" +keywords: "CustomSelection extension, superdoc CustomSelection, word CustomSelection, document CustomSelection, docx CustomSelection" +--- + +import Description from '/snippets/extensions/custom-selection.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 + + +**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) +``` + +**Parameters:** + + + The linked style to apply (with id property) + + +### `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') + + +## 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 + + +## 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 ID (e.g., 'Heading1', 'Normal') + + + Style type ('paragraph' or 'character') + + + Style definition from Word + + + + +## 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 new file mode 100644 index 0000000000..165dd1e5ad --- /dev/null +++ b/apps/docs/extensions/list-item.mdx @@ -0,0 +1,295 @@ +--- +title: ListItem extension +sidebarTitle: "List Item" +keywords: "ListItem extension, superdoc ListItem, word ListItem, document ListItem, docx ListItem" +--- + +import Description from '/snippets/extensions/list-item.mdx' + + + +## Options + +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 + +| 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 + + + + Whether editor is focused + + + Stored selection + + + Whether to show selection decoration + + + + +## 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 new file mode 100644 index 0000000000..baedc18f8a --- /dev/null +++ b/apps/docs/extensions/mention.mdx @@ -0,0 +1,36 @@ +--- +title: Mention extension +sidebarTitle: "Mention" +keywords: "Mention extension, superdoc Mention, word Mention, document Mention, docx Mention" +--- + +import Description from '/snippets/extensions/mention.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for mention elements + + +## Attributes + +Node attributes that can be set and retrieved: + + + Display name of the mentioned person + + + + Email address of the mentioned person + + + +## 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 new file mode 100644 index 0000000000..aeb1cca115 --- /dev/null +++ b/apps/docs/extensions/noderesizer.mdx @@ -0,0 +1,16 @@ +--- +title: NodeResizer extension +sidebarTitle: "Node Resizer" +keywords: "NodeResizer extension, superdoc NodeResizer, word NodeResizer, document NodeResizer, docx NodeResizer" +--- + +import Description from '/snippets/extensions/node-resizer.mdx' + + + + +## 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 new file mode 100644 index 0000000000..6d9d635564 --- /dev/null +++ b/apps/docs/extensions/ordered-list.mdx @@ -0,0 +1,127 @@ +--- +title: OrderedList extension +sidebarTitle: "Ordered List" +keywords: "OrderedList extension, superdoc OrderedList, word OrderedList, document OrderedList, docx OrderedList" +--- + +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 + + +## Commands + +### `toggleOrderedList` + +Toggle ordered list formatting + + +Converts selection to ordered list or back to paragraphs + + +**Example:** + +```javascript +editor.commands.toggleOrderedList() +``` + +### `restartListNodes` + +Restart list node numbering + + +Resets list numbering for specified nodes + + +**Example:** + +```javascript +editor.commands.restartListNodes(nodes, position) +``` + +**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 + +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleOrderedList() | `⌘/Ctrl-Shift-7` | Toggle ordered list | + + +## Source Code + +import { SourceCodeLink } from '/snippets/components/source-code-link.jsx' + + diff --git a/apps/docs/extensions/overview.mdx b/apps/docs/extensions/overview.mdx new file mode 100644 index 0000000000..428ae0f040 --- /dev/null +++ b/apps/docs/extensions/overview.mdx @@ -0,0 +1,51 @@ +--- +title: Extensions API +sidebarTitle: Overview +--- + +Extensions are the building blocks of SuperDoc. Every featureβ€”from bold text to track changesβ€”comes from an extension. + +## Understanding extensions + +Extensions provide: +- **Commands** - Actions like `toggleBold()` or `insertTable()` +- **Schema** - Define what can exist in documents +- **Behavior** - Keyboard shortcuts, input rules, events + +## Using extensions + +You don't typically configure extensions directly. SuperDoc handles it: + +```javascript +// These commands come from extensions +editor.commands.toggleBold(); // Bold extension +editor.commands.insertTable(); // Table extension +editor.commands.acceptAllChanges(); // TrackChanges extension +``` + +## Extension categories + +### Core editing +Basic document capabilities: +- **[Bold](/extensions/bold)**, **[Italic](/extensions/italic)**, **[Underline](/extensions/underline)**, **[Strike](/extensions/strike)**- Text formatting +- **[Strike](/extensions/strike)**, **[Heading](/extensions/heading)** - Document structure +- **[Lists](/extensions/bullet-list)**, **[Tables](/extensions/table)** - Bullet points and tables + +### Advanced features +Complex functionality: +- **[Track Changes](/extensions/track-changes)** - Revision tracking +- **[Comments](/extensions/comments)** - Discussions +- **[Field Annotation](/extensions/field-annotation)** - Form fields +- **[Document Section](/extensions/document-section)** - Locked sections +- **[Table](/extensions/table)** - Complex tables +- **[Search](/extensions/search)** - Find and replace + +### Custom extensions +**[Build your own β†’](/extensions/creating-extensions)** + +## How extensions work + +1. **Registration** - Extensions load with the editor +2. **Schema definition** - Define nodes/marks +3. **Command registration** - Add to `editor.commands` +4. **Event handling** - React to changes diff --git a/apps/docs/extensions/page-number.mdx b/apps/docs/extensions/page-number.mdx new file mode 100644 index 0000000000..8ce942dd30 --- /dev/null +++ b/apps/docs/extensions/page-number.mdx @@ -0,0 +1,64 @@ +--- +title: PageNumber extension +sidebarTitle: "Page Number" +keywords: "PageNumber extension, superdoc PageNumber, word PageNumber, document PageNumber, docx PageNumber" +--- + +import Description from '/snippets/extensions/page-number.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for page number elements + + +## Commands + +### `addAutoPageNumber` + +Insert an automatic page number + + +Only works in header/footer contexts + + +**Example:** + +```javascript +editor.commands.addAutoPageNumber() +``` + +**Returns:** `Function` Command function + +### `addTotalPageCount` + +Insert total page count + + +Only works in header/footer contexts + + +**Example:** + +```javascript +editor.commands.addTotalPageCount() +``` + +**Returns:** `Function` Command function + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| addAutoPageNumber() | `⌘/Ctrl-Shift-alt-p` | Insert page number | + + +## 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 new file mode 100644 index 0000000000..c218faf9eb --- /dev/null +++ b/apps/docs/extensions/paragraph.mdx @@ -0,0 +1,68 @@ +--- +title: Paragraph extension +sidebarTitle: "Paragraph" +keywords: "Paragraph extension, superdoc Paragraph, word Paragraph, document Paragraph, docx Paragraph" +--- + +import Description from '/snippets/extensions/paragraph.mdx' + + + +## Options + +Configure the extension behavior: + + + Supported heading levels + + + + HTML attributes for paragraph elements + + +## Attributes + +Node attributes that can be set and retrieved: + + + Paragraph spacing configuration + + + + Additional HTML attributes + + + + Text formatting marks + + + + Indentation settings + + + + Paragraph borders + + + + CSS class name + + + + Linked style identifier + + + + Text justification + + + + Tab stop positions + + + +## 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 new file mode 100644 index 0000000000..75c7fe9bc7 --- /dev/null +++ b/apps/docs/extensions/placeholder.mdx @@ -0,0 +1,24 @@ +--- +title: Placeholder extension +sidebarTitle: "Placeholder" +keywords: "Placeholder extension, superdoc Placeholder, word Placeholder, document Placeholder, docx Placeholder" +--- + +import Description from '/snippets/extensions/placeholder.mdx' + + + +## Options + +Configure the extension behavior: + + + Placeholder text to display when editor is empty + + + +## 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 new file mode 100644 index 0000000000..522ed898fb --- /dev/null +++ b/apps/docs/extensions/popover-plugin.mdx @@ -0,0 +1,16 @@ +--- +title: PopoverPlugin extension +sidebarTitle: "Popover Plugin" +keywords: "PopoverPlugin extension, superdoc PopoverPlugin, word PopoverPlugin, document PopoverPlugin, docx PopoverPlugin" +--- + +import Description from '/snippets/extensions/popover-plugin.mdx' + + + + +## 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 new file mode 100644 index 0000000000..35b090bc30 --- /dev/null +++ b/apps/docs/extensions/run-item.mdx @@ -0,0 +1,16 @@ +--- +title: RunItem extension +sidebarTitle: "Run Item" +keywords: "RunItem extension, superdoc RunItem, word RunItem, document RunItem, docx RunItem" +--- + +import Description from '/snippets/extensions/run-item.mdx' + + + + +## 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 new file mode 100644 index 0000000000..fc33c6c8d9 --- /dev/null +++ b/apps/docs/extensions/search.mdx @@ -0,0 +1,95 @@ +--- +title: Search extension +sidebarTitle: "Search" +keywords: "Search extension, superdoc Search, word Search, document Search, docx Search" +--- + +import Description from '/snippets/extensions/search.mdx' + + + +## Commands + +### `goToFirstMatch` + +Navigate to the first search match + + +Scrolls editor to the first match from previous search + + +**Example:** + +```javascript +editor.commands.goToFirstMatch() +``` + +### `search` + +Search for string matches in editor content + + +Returns array of SearchMatch objects with positions and IDs + + +**Example:** + +```javascript +const matches = editor.commands.search('test string') +const regexMatches = editor.commands.search(/test/i) +``` + +**Parameters:** + + + Search string or pattern + + +### `goToSearchResult` + +Navigate to a specific search match + + +Scrolls to match and selects it + + +**Example:** + +```javascript +const searchResults = editor.commands.search('test string') +editor.commands.goToSearchResult(searchResults[3]) +``` + +**Parameters:** + + + Match object to navigate to + + +## Types + +### `SearchMatch` + +Search match object + + + + Found text + + + From position + + + To position + + + ID of the search match + + + + +## 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 new file mode 100644 index 0000000000..6eecaffb57 --- /dev/null +++ b/apps/docs/extensions/shape-container.mdx @@ -0,0 +1,36 @@ +--- +title: ShapeContainer extension +sidebarTitle: "Shape Container" +keywords: "ShapeContainer extension, superdoc ShapeContainer, word ShapeContainer, document ShapeContainer, docx ShapeContainer" +--- + +import Description from '/snippets/extensions/shape-container.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for shape container elements + + +## Attributes + +Node attributes that can be set and retrieved: + + + Background color for the shape + + + + CSS style string + + + +## 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 new file mode 100644 index 0000000000..46f3735443 --- /dev/null +++ b/apps/docs/extensions/shape-textbox.mdx @@ -0,0 +1,24 @@ +--- +title: ShapeTextbox extension +sidebarTitle: "Shape Textbox" +keywords: "ShapeTextbox extension, superdoc ShapeTextbox, word ShapeTextbox, document ShapeTextbox, docx ShapeTextbox" +--- + +import Description from '/snippets/extensions/shape-textbox.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for shape textbox elements + + + +## 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 new file mode 100644 index 0000000000..d2a5e377d7 --- /dev/null +++ b/apps/docs/extensions/slash-menu.mdx @@ -0,0 +1,16 @@ +--- +title: SlashMenu extension +sidebarTitle: "Slash Menu" +keywords: "SlashMenu extension, superdoc SlashMenu, word SlashMenu, document SlashMenu, docx SlashMenu" +--- + +import Description from '/snippets/extensions/slash-menu.mdx' + + + + +## 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 new file mode 100644 index 0000000000..a96e16f10e --- /dev/null +++ b/apps/docs/extensions/strike.mdx @@ -0,0 +1,62 @@ +--- +title: Strike extension +sidebarTitle: "Strike" +keywords: "Strike extension, superdoc Strike, word Strike, document Strike, docx Strike" +--- + +import Description from '/snippets/extensions/strike.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for strikethrough elements + + +## Commands + +### `setStrike` + +Apply strikethrough formatting + +**Example:** + +```javascript +editor.commands.setStrike() +``` + +### `unsetStrike` + +Remove strikethrough formatting + +**Example:** + +```javascript +editor.commands.unsetStrike() +``` + +### `toggleStrike` + +Toggle strikethrough formatting + +**Example:** + +```javascript +editor.commands.toggleStrike() +``` + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleStrike() | `⌘/Ctrl-Shift-s` | Toggle strikethrough formatting | + + +## 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 new file mode 100644 index 0000000000..75efffe852 --- /dev/null +++ b/apps/docs/extensions/structured-content.mdx @@ -0,0 +1,302 @@ +--- +title: StructuredContent extension +sidebarTitle: "Structured Content" +keywords: "StructuredContent extension, superdoc StructuredContent, word StructuredContent, document StructuredContent, docx StructuredContent" +--- + +import Description from "/snippets/extensions/structured-content.mdx"; + + + +## Options + +Configure the extension behavior: + + + CSS class for the block + + + + HTML attributes for structured content blocks + + +## Attributes + +Node attributes that can be set and retrieved: + + + Unique identifier for the structured content block + + The `id` attribute must be a **numeric string** for valid DOCX output (per + ECMA-376 + [Β§17.5.2.18](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oe376/9bf45b56-eb07-4978-af7a-57548641667d)). + Use `Date.now().toString()` or sequential integers instead of UUIDs. + + + + + Content control tag (e.g., 'block_table_sdt') + + + + Display name for the block + + +## Commands + +### `insertStructuredContentInline` + +Inserts a structured content inline at selection. + +**Parameters:** + + + +### `insertStructuredContentBlock` + +Inserts a structured content block at selection. + +**Parameters:** + + + +### `updateStructuredContentById` + +Updates a single structured content field by its unique ID. +IDs are unique identifiers, so this will update at most one field. +If the updated node does not match the schema, it will not be updated. + +**Parameters:** + + + Unique identifier of the field + + + +### `deleteStructuredContent` + +Removes a structured content. + +**Parameters:** + + + +### `deleteStructuredContentById` + +Removes a structured content by ID. + +**Parameters:** + + + +### `deleteStructuredContentAtSelection` + +Removes a structured content at cursor, preserving its content. + +### `appendRowsToStructuredContentTable` + +Append multiple rows to the end of a table inside a structured content block. +Each inner array represents the cell values for one new row. + +**Example:** + +```javascript +editor.commands.appendRowsToStructuredContentTable({ + id: "block-123", + tableIndex: 0, + rows: [ + ["A", "B"], + ["C", "D"], + ], + copyRowStyle: true, +}); +``` + +**Parameters:** + + + Append configuration + + +## Helpers + +### `getStructuredContentBlockTags` + +Get all block-level structured content tags in the document + +**Example:** + +```javascript +const blocks = editor.helpers.getStructuredContentBlockTags(editor.state); +console.log(`Found ${blocks.length} structured content blocks`); +``` + +**Parameters:** + + + +### `getStructuredContentInlineTags` + +Get all inline structured content tags in the document + +**Example:** + +```javascript +const inlines = editor.helpers.getStructuredContentInlineTags(editor.state); +console.log(`Found ${inlines.length} inline fields`); +``` + +**Parameters:** + + + +### `getStructuredContentTablesById` + +Find all tables inside a structured content block by ID + +**Example:** + +```javascript +const tables = editor.helpers.getStructuredContentTablesById( + "block-123", + editor.state +); +console.log(`Block contains ${tables.length} table(s)`); +``` + +**Parameters:** + + + Structured content block ID + + + +### `getStructuredContentTags` + +Get all structured content tags (inline and block) in the document + +**Example:** + +```javascript +const allTags = editor.helpers.getStructuredContentTags(editor.state); +console.log(`Found ${allTags.length} structured content elements`); +``` + +**Parameters:** + + + +### `getStructuredContentTagsById` + +Get structured content tag(s) by ID + +**Example:** + +```javascript +const field = editor.helpers.getStructuredContentTagsById( + "field-123", + editor.state +); +if (field.length) console.log("Found field:", field[0].node.attrs); +``` + +**Parameters:** + + + Single ID or array of IDs to find + + + +## Types + +### `StructuredContentInlineInsert` + + + + Text content to insert + + + ProseMirror JSON + + + Node attributes + + + +### `StructuredContentBlockInsert` + + + + HTML content to insert + + + ProseMirror JSON + + + Node attributes + + + +### `StructuredContentUpdate` + + + + Replace content with text (only for structured content inline) + + + Replace content with HTML (only for structured content block) + + + Replace content with ProseMirror JSON (overrides html) + + + Update attributes only (preserves content) + + + +### `StructuredContentTableAppendRowsOptions` + + + + Structured content block identifier + + + Index of the table inside the block + + + Cell values to append + + + Clone the last row's styling when true + + + +## 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 new file mode 100644 index 0000000000..5c627839a9 --- /dev/null +++ b/apps/docs/extensions/tab.mdx @@ -0,0 +1,32 @@ +--- +title: TabNode extension +sidebarTitle: "Tab" +keywords: "TabNode extension, superdoc TabNode, word TabNode, document TabNode, docx TabNode" +--- + +import Description from '/snippets/extensions/tab.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for tab elements + + +## Attributes + +Node attributes that can be set and retrieved: + + + Width of the tab in pixels + + + +## 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 new file mode 100644 index 0000000000..ebad8692a4 --- /dev/null +++ b/apps/docs/extensions/table-cell.mdx @@ -0,0 +1,122 @@ +--- +title: TableCell extension +sidebarTitle: "Table Cell" +keywords: "TableCell extension, superdoc TableCell, word TableCell, document TableCell, docx TableCell" +--- + +import Description from '/snippets/extensions/table-cell.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for table cells + + +## Attributes + +Node attributes that can be set and retrieved: + + + Number of columns this cell spans + + + + Number of rows this cell spans + + + + Column widths array in pixels + + + + Cell background color configuration + + + + Vertical content alignment (top, middle, bottom) + + + + Internal cell padding + + + + Cell border configuration + + +## Types + +### `CellBorder` + +Cell border configuration + + + + Border width in pixels + + + Border color + + + Border style + + + +### `CellBorders` + +Cell borders object + + + + Top border + + + Right border + + + Bottom border + + + Left border + + + +### `CellMargins` + +Cell margins configuration + + + + Top margin in pixels + + + Right margin in pixels + + + Bottom margin in pixels + + + Left margin in pixels + + + +### `CellBackground` + +Cell background configuration + + + + Background color (hex without #) + + + + +## 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 new file mode 100644 index 0000000000..b8f2557f85 --- /dev/null +++ b/apps/docs/extensions/table-header.mdx @@ -0,0 +1,40 @@ +--- +title: TableHeader extension +sidebarTitle: "Table Header" +keywords: "TableHeader extension, superdoc TableHeader, word TableHeader, document TableHeader, docx TableHeader" +--- + +import Description from '/snippets/extensions/table-header.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for table headers + + +## Attributes + +Node attributes that can be set and retrieved: + + + Number of columns this header spans + + + + Number of rows this header spans + + + + Column widths array in pixels + + + +## 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 new file mode 100644 index 0000000000..7b525e8478 --- /dev/null +++ b/apps/docs/extensions/table-row.mdx @@ -0,0 +1,140 @@ +--- +title: TableRow extension +sidebarTitle: "Table Row" +keywords: "TableRow extension, superdoc TableRow, word TableRow, document TableRow, docx TableRow" +--- + +import Description from '/snippets/extensions/table-row.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for table rows + + +## Attributes + +Node attributes that can be set and retrieved: + + + Fixed row height in pixels + + + + Indicates row should not split across pages + + +## Types + +### `CnfStyle` + + + + Specifies that the object has inherited the conditional properties applied to the even numbered horizontal bands of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the even numbered vertical bands of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the first column of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the first row of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the cell that is in the first row and first column of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the cell that is in the first row and last column of the parent object. + + + Specifies that the object has inherited the conditional properties +applied to the last column of the parent object. + + + Specifies that the object has inherited the conditional properties +applied to the last row of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the cell that is in the last row and first column of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the cell that is in the last row and last column of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the odd numbered horizontal bands of the parent object. + + + Specifies that the object has inherited the conditional properties applied to the odd numbered vertical bands of the parent object. + + + +### `TableRowProperties` + + + + Indicates that this row should not be split across pages when paginating/exporting. + + + Specifies the set of conditional table style formatting properties which have been applied to this row + + + Specifies the HTML div information which is associated with this row. + + + Specifies the number of grid columns to be that should be left empty after the last cell in this row. + + + Specifies the number of grid columns that should be skipped before the first cell in this row. + + + Specifies that the glyph representing the end character of current table row shall not be displayed in the current document. + + + Specifies the overall justification of the contents of this row. + + + Specifies the amount of spacing that shall be applied between the cells in this row. + + + The size of the spacing in twenieths of a point (1/1440 of an inch). + + + The type of spacing. + + + Specifies that this row is to be repeated as a header row at the top of each page on which the table is displayed. + + + The rule for the row height. + + + Specifies the preferred width for the total number of grid columns after this table row. + + + The width in twenieths of a point (1/1440 of an inch). + + + The type of width. + + + Specifies the preferred width for the total number of grid columns before this table row. + + + The width in twenieths of a point (1/1440 of an inch). + + + The type of width. + + + + +## 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 new file mode 100644 index 0000000000..5fb4a54df8 --- /dev/null +++ b/apps/docs/extensions/table.mdx @@ -0,0 +1,832 @@ +--- +title: Table extension +sidebarTitle: "Table" +keywords: "Table extension, superdoc Table, word Table, document Table, docx Table" +--- + +import Description from '/snippets/extensions/table.mdx' + + + +## Options + +Configure the extension behavior: + + + Default HTML attributes for all tables + + + + Enable column resizing functionality + + + + Width of resize handles in pixels + + + + Minimum cell width constraint in pixels + + + + Allow resizing of the last column + + + + Enable selecting the entire table node + + +## Attributes + +Node attributes that can be set and retrieved: + + + Table indentation configuration + + + + Border styling for this table + + + + CSS border-collapse property + + + + Table alignment ('left', 'center', 'right') + + + + Cell spacing in pixels for this table + + +## Commands + +### `insertTable` + +Insert a new table into the document + +**Example:** + +```javascript +editor.commands.insertTable() +editor.commands.insertTable({ rows: 3, cols: 3, withHeaderRow: true }) +``` + +**Parameters:** + + + Table configuration options + + +### `deleteTable` + +Delete the entire table containing the cursor + +**Example:** + +```javascript +editor.commands.deleteTable() +``` + +### `addColumnBefore` + +Add a column before the current column + + +Preserves cell attributes from current column + + +**Example:** + +```javascript +editor.commands.addColumnBefore() +``` + +### `addColumnAfter` + +Add a column after the current column + + +Preserves cell attributes from current column + + +**Example:** + +```javascript +editor.commands.addColumnAfter() +``` + +**Returns:** `Function` Command + +### `deleteColumn` + +Delete the column containing the cursor + +**Example:** + +```javascript +editor.commands.deleteColumn() +``` + +**Returns:** `Function` Command + +### `addRowBefore` + +Add a row before the current row + + +Preserves cell attributes from current row + + +**Example:** + +```javascript +editor.commands.addRowBefore() +``` + +**Returns:** `Function` Command + +### `addRowAfter` + +Add a row after the current row + + +Preserves cell attributes from current row + + +**Example:** + +```javascript +editor.commands.addRowAfter() +``` + +**Returns:** `Function` Command + +### `deleteRow` + +Delete the row containing the cursor + +**Example:** + +```javascript +editor.commands.deleteRow() +``` + +**Returns:** `Function` Command + +### `mergeCells` + +Merge selected cells into one + + +Content from all cells is preserved + + +**Example:** + +```javascript +editor.commands.mergeCells() +``` + +**Returns:** `Function` Command + +### `splitCell` + +Split a merged cell back into individual cells + +**Example:** + +```javascript +editor.commands.splitCell() +``` + +**Returns:** `Function` Command - true if split, false if position invalid + +### `splitSingleCell` + +Split a single unmerged cell into two cells horizontally + + +Different from splitCell which splits merged cells back to original cells + + +**Example:** + +```javascript +editor.commands.splitSingleCell() +``` + +**Returns:** `Function` Command - true if split, false if position invalid + +### `mergeOrSplit` + +Toggle between merge and split cells based on selection + + +Merges if multiple cells selected, splits if merged cell selected + + +**Example:** + +```javascript +editor.commands.mergeOrSplit() +``` + +**Returns:** `Function` Command + +### `toggleHeaderColumn` + +Toggle the first column as header column + +**Example:** + +```javascript +editor.commands.toggleHeaderColumn() +``` + +**Returns:** `Function` Command + +### `toggleHeaderRow` + +Toggle the first row as header row + +**Example:** + +```javascript +editor.commands.toggleHeaderRow() +``` + +**Returns:** `Function` Command + +### `toggleHeaderCell` + +Toggle current cell as header cell + +**Example:** + +```javascript +editor.commands.toggleHeaderCell() +``` + +**Returns:** `Function` Command + +### `setCellAttr` + +Set an attribute on selected cells + +**Example:** + +```javascript +editor.commands.setCellAttr('background', { color: 'ff0000' }) +setCellAttr('verticalAlign', 'middle') +``` + +**Parameters:** + + + Attribute name + + + Attribute value + + +**Returns:** `Function` Command + +### `goToNextCell` + +Navigate to the next cell (Tab behavior) + +**Example:** + +```javascript +editor.commands.goToNextCell() +``` + +**Returns:** `Function` Command + +### `goToPreviousCell` + +Navigate to the previous cell (Shift+Tab behavior) + +**Example:** + +```javascript +editor.commands.goToPreviousCell() +``` + +**Returns:** `Function` Command + +### `fixTables` + +Fix table structure inconsistencies + + +Repairs malformed tables and normalizes structure + + +**Example:** + +```javascript +editor.commands.fixTables() +``` + +**Returns:** `Function` Command + +### `setCellSelection` + +Set cell selection programmatically + +**Example:** + +```javascript +editor.commands.setCellSelection({ anchorCell: 10, headCell: 15 }) +``` + +**Parameters:** + + + Cell selection coordinates + + +**Returns:** `Function` Command + +### `setCellBackground` + +Set background color for selected cells + +**Example:** + +```javascript +editor.commands.setCellBackground('#ff0000') +editor.commands.setCellBackground('ff0000') +``` + +**Parameters:** + + + Color value (hex with or without #) + + +### `deleteCellAndTableBorders` + +Remove all borders from table and its cells + + +Sets all border sizes to 0 + + +**Example:** + +```javascript +editor.commands.deleteCellAndTableBorders() +``` + +**Returns:** `Function` Command + +## 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() | `Delete` | Delete table when all cells selected | + +## Types + +### `ThemeColor` + +Theme color options + +### `ShadingPattern` + +Shading pattern options + +### `ShadingProperties` + +Shading properties + + + + Shading color (hex without # or "auto" for automatic) + + + Shading fill color (hex without # or "auto" for automatic) + + + Theme color name + + + Theme fill name + + + Theme fill shade (0-255 in hex format without #) + + + Theme fill tint (0-255 in hex format without #) + + + Theme shade (0-255 in hex format without #) + + + Theme tint (0-255 in hex format without #) + + + Shading pattern + + + +### `TableMeasurement` + +Table width options + + + + Width value in twips + + + Table width type (dxa=twips, pct=percentage, auto=automatic) + + + +### `TableLook` + +Table look options + + + + Specifies that the first column conditional formatting should be applied + + + Specifies that the first row conditional formatting should be applied + + + Specifies that the last column conditional formatting should be applied + + + Specifies that the last row conditional formatting should be applied + + + Specifies that no horizontal banding conditional formatting should be applied + + + Specifies that no vertical banding conditional formatting should be applied + + + +### `FloatingTableProperties` + +Floating table properties + + + + Specifies the minimum distance in twips which shall be maintained between the current floating table and the edge of text in the paragraph which is to the left of this floating table. + + + Specifies the minimum distance in twips which shall be maintained between the current floating table and the edge of text in the paragraph which is to the right of this floating table. + + + Specifies the minimum distance in twips which shall be maintained between the current floating table and the bottom edge of text in the paragraph which is above this floating table. + + + Specifies the minimum distance in twips which shall be maintained between the current floating table and the top edge of text in the paragraph which is below this floating table. + + + Specifies and absolute horizontal position for the floating table. The position is measured from the horizontal anchor point (horzAnchor) in twips. + + + Specifies and absolute vertical position for the floating table. The position is measured from the vertical anchor point (vertAnchor) in twips. + + + Horizontal anchor point for tblpX + + + Vertical anchor point for tblpY + + + Specifies a relative horizontal position for the floating table. Supercedes tblpX if both are specified. + + + Specifies a relative vertical position for the floating table. Supercedes tblpY if both are specified. + + + +### `TableBorderSpec` + +Table border specification + + + + Border style (e.g., 'single', 'double', 'dashed', etc.) + + + Border color (hex without #, e.g., 'FF0000' for red) + + + Theme color name + + + Theme tint (0-255 in hex format without #) + + + Theme shade (0-255 in hex format without #) + + + Border size in eighths of a point (e.g., 8 = 1pt, 16 = 2pt) + + + Space in points between border and text + + + Whether the border has a shadow + + + Whether the border is a frame + + + +### `TableBorders` + +Table borders properties + + + + Bottom border specification + + + End (right in LTR, left in RTL) border specification + + + Inside horizontal border specification + + + Inside vertical border specification + + + Left border specification + + + Right border specification + + + Start (left in LTR, right in RTL) border specification + + + Top border specification + + + +### `TableBorders` + +Table borders object + + + + Top border configuration + + + Right border configuration + + + Bottom border configuration + + + Left border configuration + + + Inside horizontal borders + + + Inside vertical borders + + + +### `TableCellMargins` + +Table cell margin properties + + + + Top cell margin + + + Left cell margin + + + Bottom cell margin + + + Start cell margin (left in LTR, right in RTL) + + + End cell margin (right in LTR, left in RTL) + + + Right cell margin + + + +### `TableProperties` + +Table properties + + + + Specifies that the cells with this table shall be visually represented in a right to left direction + + + The alignment of the set of rows which are part of the current table. + + + Shading properties for the table + + + Caption text for the table + + + Description text for the table + + + Cell spacing + + + Table indentation + + + Table layout algorithm + + + Various boolean flags that affect the rendering of the table + + + Specifies whether the current table should allow other floating tables to overlap its extents when the tables are displayed in a document + + + Reference to table style ID + + + Number of columns for which the table style is applied + + + Number of rows for which the table style is applied + + + Table width + + + Floating table properties + + + Table border configuration + + + +### `ColWidth` + +Column width definition + + + + Column width in twips + + + +### `TableGrid` + +Table grid definition + + + + Array of column widths in twips + + + +### `TableConfig` + +Table configuration options + + + + Number of rows to create + + + Number of columns to create + + + Create first row as header row + + + +### `TableIndent` + +Table indentation configuration + + + + Indent width in pixels + + + Indent type + + + +### `CellSelectionPosition` + +Cell selection position + + + + Starting cell position + + + Ending cell position + + + +### `CurrentCellInfo` + +Current cell information + + + + Selected rectangle information + + + The cell node + + + Cell attributes + + + +### `CellBorder` + +Cell border configuration + + + + Border width in pixels + + + Border color + + + Border style + + + +### `CellBorders` + +Cell borders object + + + + Top border + + + Right border + + + Bottom border + + + Left border + + + +### `TableBorder` + +Table border configuration + + + + Border width in pixels + + + Border color (hex or CSS color) + + + Border style (solid, dashed, dotted) + + + +### `BorderOptions` + +Border creation options + + + + Border width in pixels + + + Border color (hex) + + + + +## 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 new file mode 100644 index 0000000000..4f36e19ad3 --- /dev/null +++ b/apps/docs/extensions/text-align.mdx @@ -0,0 +1,86 @@ +--- +title: TextAlign extension +sidebarTitle: "Text Align" +keywords: "TextAlign extension, superdoc TextAlign, word TextAlign, document TextAlign, docx TextAlign" +--- + +import Description from '/snippets/extensions/text-align.mdx' + + + +## Options + +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) + + +**Example:** + +```javascript +editor.commands.setTextAlign('center') +editor.commands.setTextAlign('justify') +``` + +**Parameters:** + + + Alignment value (left, center, right, justify) + + +### `unsetTextAlign` + +Remove text alignment (reset to default) + + +Resets alignment to the default value + + +**Example:** + +```javascript +editor.commands.unsetTextAlign() +``` + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| setTextAlign('left')() | `⌘/Ctrl-Shift-l` | Align text left | +| setTextAlign('center')() | `⌘/Ctrl-Shift-e` | Align text center | +| setTextAlign('right')() | `⌘/Ctrl-Shift-r` | Align text right | +| setTextAlign('justify')() | `⌘/Ctrl-Shift-j` | Justify text | + + +## 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 new file mode 100644 index 0000000000..6f45a82139 --- /dev/null +++ b/apps/docs/extensions/text-indent.mdx @@ -0,0 +1,120 @@ +--- +title: TextIndent extension +sidebarTitle: "Text Indent" +keywords: "TextIndent extension, superdoc TextIndent, word TextIndent, document TextIndent, docx TextIndent" +--- + +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` + +Set text indentation + + +Accepts any valid CSS unit (in, cm, px, em, etc.) + + +**Example:** + +```javascript +// Set to 0.5 inches +setTextIndent('0.5in') + +// Set to 2 centimeters +setTextIndent('2cm') +``` + +**Parameters:** + + + Indentation value with unit (e.g., '0.5in', '2cm') + + +**Returns:** `Function` Command function + +### `unsetTextIndent` + +Remove text indentation + + +Removes all indentation from the selected nodes + + +**Example:** + +```javascript +editor.commands.unsetTextIndent() +``` + +**Returns:** `Function` Command function + +### `increaseTextIndent` + +Increase text indentation + + +Creates initial indent if none exists + + +**Example:** + +```javascript +editor.commands.increaseTextIndent() +``` + +**Returns:** `Function` Command function + +### `decreaseTextIndent` + +Decrease text indentation + + +Removes indentation completely if it reaches 0 or below + + +**Example:** + +```javascript +editor.commands.decreaseTextIndent() +``` + +**Returns:** `Function` Command function + + +## 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 new file mode 100644 index 0000000000..f5c93d23c5 --- /dev/null +++ b/apps/docs/extensions/text-style.mdx @@ -0,0 +1,67 @@ +--- +title: TextStyle extension +sidebarTitle: "Text Style" +keywords: "TextStyle extension, superdoc TextStyle, word TextStyle, document TextStyle, docx TextStyle" +--- + +import Description from '/snippets/extensions/text-style.mdx' + + + +## Options + +Configure the extension behavior: + + + Custom HTML attributes to apply to text style spans + + +## Attributes + +Node attributes that can be set and retrieved: + + + Style identifier for referencing predefined styles + + +## Commands + +### `removeEmptyTextStyle` + +Remove empty text style marks + + +Automatically checks if any style attributes exist before removal + + +**Example:** + +```javascript +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 + +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 new file mode 100644 index 0000000000..95bf25cf8c --- /dev/null +++ b/apps/docs/extensions/text-transform.mdx @@ -0,0 +1,32 @@ +--- +title: TextTransform extension +sidebarTitle: "Text Transform" +keywords: "TextTransform extension, superdoc TextTransform, word TextTransform, document TextTransform, docx TextTransform" +--- + +import Description from '/snippets/extensions/text-transform.mdx' + + + +## Options + +Configure the extension behavior: + + + Mark types to apply text transform to + + +## Attributes + +Node attributes that can be set and retrieved: + + + Text transform value (uppercase, lowercase, capitalize, none) + + + +## 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 new file mode 100644 index 0000000000..ea610473d1 --- /dev/null +++ b/apps/docs/extensions/track-changes.mdx @@ -0,0 +1,79 @@ +--- +title: Track Changes Extension +sidebarTitle: Track Changes +--- + +Track Changes records all edits with author attribution and timestamps, exactly like Microsoft Word. + +## Usage + +Enable through document mode: + +```javascript +// Start tracking +superdoc.setDocumentMode('suggesting'); +``` + +## Commands + +```javascript +// Switch modes (controls tracking) +superdoc.setDocumentMode('suggesting'); // Enable tracking +superdoc.setDocumentMode('editing'); // Disable tracking + +// Review changes +editor.commands.acceptChange(); +editor.commands.rejectChange(); +editor.commands.acceptAllChanges(); +editor.commands.rejectAllChanges(); + +// Navigate +editor.commands.goToNextChange(); +editor.commands.goToPreviousChange(); + +// View modes +editor.commands.toggleTrackChangesShowOriginal(); +editor.commands.toggleTrackChangesShowFinal(); +``` + +## Working with changes + +```javascript +import { trackChangesHelpers } from '@harbour-enterprises/superdoc'; + +// Get all changes +const changes = trackChangesHelpers.getAllChanges(editor.state); + +// Filter by user +const userChanges = trackChangesHelpers.getChangesByUser( + editor.state, + 'john@company.com' +); + +// Check state +const isTracking = trackChangesHelpers.isTrackingEnabled(editor.state); +``` + +## Change types + +- **Insertions** - Green underline +- **Deletions** - Red strikethrough +- **Format changes** - Yellow highlight + +Each change includes: +- User information +- Timestamp +- Unique ID + +## Export behavior + +Changes export to DOCX as Word revisions: + +```javascript +// With changes +await superdoc.export(); + +// Accept all first +editor.commands.acceptAllChanges(); +await superdoc.export(); +``` diff --git a/apps/docs/extensions/underline.mdx b/apps/docs/extensions/underline.mdx new file mode 100644 index 0000000000..48ed29cd39 --- /dev/null +++ b/apps/docs/extensions/underline.mdx @@ -0,0 +1,89 @@ +--- +title: Underline extension +sidebarTitle: "Underline" +keywords: "Underline extension, superdoc Underline, word Underline, document Underline, docx Underline" +--- + +import Description from '/snippets/extensions/underline.mdx' + + + +## Options + +Configure the extension behavior: + + + HTML attributes for underline elements + + +## Attributes + +Node attributes that can be set and retrieved: + + + Style of underline + + +## Commands + +### `setUnderline` + +Apply underline formatting + +**Example:** + +```javascript +editor.commands.setUnderline() +``` + +**Returns:** `Function` Command + +### `unsetUnderline` + +Remove underline formatting + +**Example:** + +```javascript +editor.commands.unsetUnderline() +``` + +**Returns:** `Function` Command + +### `toggleUnderline` + +Toggle underline formatting + +**Example:** + +```javascript +editor.commands.toggleUnderline() +``` + +**Returns:** `Function` Command + +## Keyboard Shortcuts + +| Command | Shortcut | Description | +|---------|----------|-------------| +| toggleUnderline() | `⌘/Ctrl-u` | Toggle underline formatting | +| toggleUnderline() | `⌘/Ctrl-U` | Toggle underline formatting (uppercase) | + +## Types + +### `UnderlineConfig` + +Underline style configuration + + + + Style variant + + + + +## 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 new file mode 100644 index 0000000000..89f829f197 --- /dev/null +++ b/apps/docs/getting-started/ai-agents.mdx @@ -0,0 +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" +--- + +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 + +```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', + } +}); + +editor.commands.insertContent(aiContent, { contentType: 'html' }); +``` +[See complete example β†’](https://github.com/Harbour-Enterprises/SuperDoc/tree/develop/examples/agentic-slack-redlining-example) + +## The AI Document Workflow + +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(); +``` + +### Three Ways to Work + +**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 + +[See detailed import options β†’](/getting-started/import-export#ai-integration-pattern) + +## Quick access for AI assistants + +Working with Cursor, Claude, or ChatGPT? Give your assistant our docs: + +```javascript +// Quick reference +'https://docs.superdoc.dev/llms.txt' + +// Complete documentation +'https://docs.superdoc.dev/llms-full.txt' + +// MCP server +'https://docs.superdoc.dev/mcp' +``` + +Drop these URLs into your AI's context. Now it knows SuperDoc. \ No newline at end of file diff --git a/apps/docs/getting-started/configuration.mdx b/apps/docs/getting-started/configuration.mdx new file mode 100644 index 0000000000..52366ef8a4 --- /dev/null +++ b/apps/docs/getting-started/configuration.mdx @@ -0,0 +1,155 @@ +--- +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/fonts.mdx b/apps/docs/getting-started/fonts.mdx new file mode 100644 index 0000000000..30043055dc --- /dev/null +++ b/apps/docs/getting-started/fonts.mdx @@ -0,0 +1,7 @@ +--- +title: Font Support +--- + +Loading toolbar font config... + +{(() => { window.location.href = '/modules/toolbar#font-configuration'; })()} diff --git a/apps/docs/getting-started/frameworks/angular.mdx b/apps/docs/getting-started/frameworks/angular.mdx new file mode 100644 index 0000000000..d0a10fb08e --- /dev/null +++ b/apps/docs/getting-started/frameworks/angular.mdx @@ -0,0 +1,99 @@ +--- +title: Angular +keywords: "angular docx editor, angular word component, superdoc angular, angular document editor, angular integration" +--- + +SuperDoc works with Angular through direct DOM manipulation. + +## Installation + +```bash +npm install @harbour-enterprises/superdoc +``` + +## Basic component + +```typescript +import { Component, ElementRef, ViewChild, OnInit, OnDestroy } from '@angular/core'; +import { SuperDoc } from '@harbour-enterprises/superdoc'; + +@Component({ + selector: 'app-document-editor', + template: ` +
+ `, + styles: [` + .editor-container { + height: 700px; + } + `] +}) +export class DocumentEditorComponent implements OnInit, OnDestroy { + @ViewChild('editor', { static: true }) editorElement!: ElementRef; + private superdoc: SuperDoc | null = null; + + ngOnInit() { + this.superdoc = new SuperDoc({ + selector: this.editorElement.nativeElement, + document: 'contract.docx' + }); + } + + ngOnDestroy() { + this.superdoc = null; + } + + async exportDocument() { + if (this.superdoc) { + await this.superdoc.export(); + } + } +} +``` + +## With file input + +```typescript +@Component({ + selector: 'app-editor', + template: ` + +
+ ` +}) +export class EditorComponent { + @ViewChild('editor', { static: false }) editorElement!: ElementRef; + private superdoc: SuperDoc | null = null; + + onFileSelected(event: Event) { + const file = (event.target as HTMLInputElement).files?.[0]; + if (file && this.editorElement) { + this.superdoc = new SuperDoc({ + selector: this.editorElement.nativeElement, + document: file + }); + } + } +} +``` + +## Service pattern + +```typescript +@Injectable({ providedIn: 'root' }) +export class DocumentService { + private superdoc: SuperDoc | null = null; + + initialize(element: HTMLElement, document: File | string) { + this.superdoc = new SuperDoc({ + selector: element, + document + }); + return this.superdoc; + } + + destroy() { + this.superdoc = null; + } +} +``` \ No newline at end of file diff --git a/apps/docs/getting-started/frameworks/blazor.mdx b/apps/docs/getting-started/frameworks/blazor.mdx new file mode 100644 index 0000000000..6c00bb210c --- /dev/null +++ b/apps/docs/getting-started/frameworks/blazor.mdx @@ -0,0 +1,199 @@ +--- +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 new file mode 100644 index 0000000000..0a244afdc0 --- /dev/null +++ b/apps/docs/getting-started/frameworks/nextjs.mdx @@ -0,0 +1,126 @@ +--- +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 new file mode 100644 index 0000000000..375c6f9970 --- /dev/null +++ b/apps/docs/getting-started/frameworks/nuxt.mdx @@ -0,0 +1,130 @@ +--- +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 new file mode 100644 index 0000000000..236b7f8122 --- /dev/null +++ b/apps/docs/getting-started/frameworks/php.mdx @@ -0,0 +1,165 @@ +--- +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 new file mode 100644 index 0000000000..a23c1e324f --- /dev/null +++ b/apps/docs/getting-started/frameworks/react.mdx @@ -0,0 +1,268 @@ +--- +title: React Integration +sidebarTitle: React +keywords: "react docx editor, react word component, superdoc react, microsoft word react, document editor react hooks" +--- +SuperDoc works with React 16.8+ (hooks) and React 18+ (concurrent features). + +## Install + +```bash +npm install @harbour-enterprises/superdoc +``` + +## Basic Setup + +```jsx +import { useEffect, useRef } from 'react'; +import { SuperDoc } from '@harbour-enterprises/superdoc'; +import '@harbour-enterprises/superdoc/style.css'; + +function DocEditor({ document }) { + const containerRef = useRef(null); + const superdocRef = useRef(null); + + useEffect(() => { + if (!containerRef.current) return; + + superdocRef.current = new SuperDoc({ + selector: containerRef.current, + document + }); + + return () => { + superdocRef.current = null; + }; + }, [document]); + + return
; +} +``` + +## 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'; + +const DocEditor = forwardRef(({ document, user, onReady }, ref) => { + const containerRef = useRef(null); + const superdocRef = useRef(null); + + useImperativeHandle(ref, () => ({ + export: (options) => superdocRef.current?.export(options), + setMode: (mode) => superdocRef.current?.setDocumentMode(mode), + getHTML: () => superdocRef.current?.getHTML() + })); + + useEffect(() => { + if (!containerRef.current) return; + + superdocRef.current = new SuperDoc({ + selector: containerRef.current, + document, + user, + onReady: () => onReady?.(superdocRef.current) + }); + + return () => { + superdocRef.current = null; + }; + }, [document, user, onReady]); + + return
; +}); + +// Usage +function App() { + const editorRef = useRef(); + + const handleExport = async () => { + await editorRef.current.export({ isFinalDoc: true }); + }; + + return ( + <> + + + console.log('Ready', editor)} + /> + + ); +} +``` + +## File Upload + +```jsx +function FileEditor() { + const [file, setFile] = useState(null); + const editorRef = useRef(); + + const handleFile = (e) => { + setFile(e.target.files[0]); + }; + + const handleExport = async () => { + const blob = await editorRef.current?.export({ + isFinalDoc: true + }); + // Download blob... + }; + + return ( + <> + + {file && ( + <> + + + + )} + + ); +} +``` + +## TypeScript + +```tsx +import { useEffect, useRef, forwardRef } from 'react'; +import { SuperDoc } from '@harbour-enterprises/superdoc'; +import type { SuperDocConfig } from '@harbour-enterprises/superdoc'; + +interface EditorProps { + document: string | File | Blob; + userId: string; + onReady?: (editor: SuperDoc) => void; +} + +interface EditorRef { + export: (options?: ExportOptions) => Promise; + setMode: (mode: 'editing' | 'viewing' | 'suggesting') => void; + getHTML: () => string[]; +} + +const DocEditor = forwardRef( + ({ document, userId, onReady }, ref) => { + const containerRef = useRef(null); + const superdocRef = useRef(null); + + useImperativeHandle(ref, () => ({ + export: async (options) => { + if (!superdocRef.current) throw new Error('Editor not ready'); + return await superdocRef.current.export(options); + }, + setMode: (mode) => { + superdocRef.current?.setDocumentMode(mode); + }, + getHTML: () => { + return superdocRef.current?.getHTML() || []; + } + })); + + useEffect(() => { + if (!containerRef.current) return; + + const config: SuperDocConfig = { + selector: containerRef.current, + document, + user: { + name: userId, + email: `${userId}@company.com` + }, + onReady: () => onReady?.(superdocRef.current!) + }; + + superdocRef.current = new SuperDoc(config); + + return () => { + superdocRef.current = null; + }; + }, [document, userId, onReady]); + + return
; + } +); +``` + +## SSR Support + +For Next.js or other SSR frameworks: + +```jsx +import dynamic from 'next/dynamic'; + +const DocEditor = dynamic( + () => import('./DocEditor'), + { + ssr: false, + loading: () =>
Loading editor...
+ } +); + +// Or manually check for client-side +function SafeEditor(props) { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + if (!mounted) return
Loading...
; + + return ; +} +``` + +## Custom Hook + +```jsx +function useSuperDoc(config) { + const [ready, setReady] = useState(false); + const superdocRef = useRef(null); + + useEffect(() => { + if (!config.selector) return; + + superdocRef.current = new SuperDoc({ + ...config, + onReady: () => { + setReady(true); + config.onReady?.(); + } + }); + + return () => { + superdocRef.current = null; + setReady(false); + }; + }, [config.selector, config.document]); + + return { + editor: superdocRef.current, + ready, + export: (options) => superdocRef.current?.export(options), + setMode: (mode) => superdocRef.current?.setDocumentMode(mode) + }; +} +``` + +## 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 diff --git a/apps/docs/getting-started/frameworks/ruby-on-rails.mdx b/apps/docs/getting-started/frameworks/ruby-on-rails.mdx new file mode 100644 index 0000000000..f821c35f6c --- /dev/null +++ b/apps/docs/getting-started/frameworks/ruby-on-rails.mdx @@ -0,0 +1,141 @@ +--- +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 new file mode 100644 index 0000000000..d5891a2881 --- /dev/null +++ b/apps/docs/getting-started/frameworks/svelte.mdx @@ -0,0 +1,104 @@ +--- +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 new file mode 100644 index 0000000000..b35d836e41 --- /dev/null +++ b/apps/docs/getting-started/frameworks/vanilla-js.mdx @@ -0,0 +1,181 @@ +--- +title: Vanilla JavaScript +sidebarTitle: Vanilla JS +keywords: "vanilla javascript docx, plain js word editor, superdoc vanilla, no framework docx, pure javascript editor" +--- + +SuperDoc works with plain JavaScript. No framework required. + +## Basic Setup + + + +```html CDN + + + + + + +
+ + + + +``` + +```javascript NPM/Bundler +import { SuperDoc } from '@harbour-enterprises/superdoc'; +import '@harbour-enterprises/superdoc/style.css'; + +const superdoc = new SuperDoc({ + selector: '#editor', + document: 'contract.docx' +}); +``` + +
+ +## Load Documents + + + +```javascript File Upload +const fileInput = document.querySelector('input[type="file"]'); +fileInput.addEventListener('change', (e) => { + const file = e.target.files[0]; + if (!file) return; + + new SuperDoc({ + selector: '#editor', + document: file + }); +}); +``` + +```javascript Fetch API +fetch('/api/documents/123') + .then(res => res.blob()) + .then(blob => { + // Convert Blob to File (required) + const file = new File([blob], 'document.docx', { + type: blob.type || 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' + }); + + new SuperDoc({ + selector: '#editor', + document: file + }); + }); +``` + +```javascript Direct URL +new SuperDoc({ + selector: '#editor', + document: 'https://example.com/contract.docx' +}); +``` + + + +## Complete Example + + + +```html CDN + + + + + + +
+ + + + +
+ +
+ + + + +``` + +```javascript NPM/Bundler +import { SuperDoc } from '@harbour-enterprises/superdoc'; +import '@harbour-enterprises/superdoc/style.css'; + +let superdoc = null; + +// File upload +document.getElementById('file-input').addEventListener('change', (e) => { + const file = e.target.files[0]; + if (!file) return; + + superdoc = new SuperDoc({ + selector: '#editor', + document: file, + documentMode: 'editing' + }); +}); + +// Mode controls +document.getElementById('mode-edit').addEventListener('click', () => { + superdoc?.setDocumentMode('editing'); +}); + +document.getElementById('mode-review').addEventListener('click', () => { + superdoc?.setDocumentMode('suggesting'); +}); + +// Export +document.getElementById('export-btn').addEventListener('click', async () => { + await superdoc?.export({ isFinalDoc: true }); +}); +``` + +
+ +## Next Steps + +- [API Reference](/core/superdoc/configuration) - Configuration options +- [React Integration](/getting-started/frameworks/react) - Using with React +- [Vue Integration](/getting-started/frameworks/vue) - Using with Vue \ No newline at end of file diff --git a/apps/docs/getting-started/frameworks/vue.mdx b/apps/docs/getting-started/frameworks/vue.mdx new file mode 100644 index 0000000000..1198fbc8d1 --- /dev/null +++ b/apps/docs/getting-started/frameworks/vue.mdx @@ -0,0 +1,209 @@ +--- +title: Vue Integration +sidebarTitle: Vue +keywords: "vue docx editor, vue word component, superdoc vue, vue document editor, vue composition api" +--- +SuperDoc works with Vue 3.0+ using Composition API, Options API, or ` +``` + +```vue Options API + + + +``` + + + +## Full Component + +Build a reusable DOCX editor component with controls: + +```vue + + + + + +``` + +## Handle File Uploads + +```vue + + + +``` + +## TypeScript Support + +```vue + +``` + +## 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 diff --git a/apps/docs/getting-started/import-export.mdx b/apps/docs/getting-started/import-export.mdx new file mode 100644 index 0000000000..b0f97a9ddf --- /dev/null +++ b/apps/docs/getting-started/import-export.mdx @@ -0,0 +1,263 @@ +--- +title: Import/Export +sidebarTitle: Import/Export +keywords: "import, export, import types, export types, docx to pdf, markdown to docx" +--- + +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. + +## Philosophy + +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. + +## Supported Formats + +| 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 | + +## When to Use Each Format + +### Use DOCX/JSON for: +- Preserving all formatting +- Round-trip editing +- Complex documents +- Production workflows + +### 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) +new SuperDoc({ + selector: '#editor', + document: docxFile +}); + +// HTML content (structure preserved, styles stripped) +new SuperDoc({ + selector: '#editor', + document: blankDocx, // Must have styles defined + html: '

Title

Content

' +}); + +// Markdown content (converted to Word structure) +new SuperDoc({ + selector: '#editor', + document: blankDocx, + markdown: '# Title\n\nContent with **formatting**' +}); + +// JSON schema (full control) +new SuperDoc({ + selector: '#editor', + document: blankDocx, + jsonOverride: documentSchema +}); +``` + +### Method 2: Insert into Existing Document + +Add content to an already-loaded document using commands. + +```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 +}); +``` + +## HTML Import/Export Behavior + +### What Gets Preserved + +| 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 | +| `