Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ tests/visual/ Visual regression tests (Playwright + R2 baselines)
- **Editing commands/behavior**: Modify `super-editor/src/extensions/`
- **State bridging**: Modify `PresentationEditor.ts`

## JSDoc types

Many packages use `.js` files with JSDoc `@typedef` for type definitions (e.g., `packages/superdoc/src/core/types/index.js`). These typedefs ARE the published type declarations — `vite-plugin-dts` generates `.d.ts` files from them.

- **Keep JSDoc typedefs in sync with code.** If a function destructures `{ a, b, c }`, the `@typedef` must include all three properties. Missing properties become type errors for consumers.
- **Verify types after adding parameters.** When adding a parameter to a function, update its `@typedef` or `@param` JSDoc. Build with `pnpm run --filter superdoc build:es` and check the generated `.d.ts` in `dist/`.
- **Workspace packages don't publish types.** `@superdoc/common`, `@superdoc/contracts`, etc. are private. If a public API references their types, those types must be inlined or resolved through path aliases — consumers can't resolve workspace packages.

## Commands

- `pnpm build` - Build all packages
Expand Down
131 changes: 82 additions & 49 deletions apps/docs/getting-started/frameworks/angular.mdx
Original file line number Diff line number Diff line change
@@ -1,99 +1,132 @@
---
title: Angular
title: Angular Integration
sidebarTitle: Angular
keywords: "angular docx editor, angular word component, superdoc angular, angular document editor, angular integration"
---

SuperDoc works with Angular through direct DOM manipulation.
SuperDoc works with Angular through direct DOM manipulation. No wrapper needed.

## Installation
## Install

```bash
npm install superdoc
```

## Basic component
## Basic setup

```typescript
import { Component, ElementRef, ViewChild, OnInit, OnDestroy } from '@angular/core';
import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

@Component({
selector: 'app-document-editor',
template: `
<div #editor class="editor-container"></div>
`,
styles: [`
.editor-container {
height: 700px;
}
`]
selector: 'app-editor',
template: `<div #editor style="height: 700px"></div>`,
})
export class DocumentEditorComponent implements OnInit, OnDestroy {
@ViewChild('editor', { static: true }) editorElement!: ElementRef;
export class EditorComponent implements OnInit, OnDestroy {
@ViewChild('editor', { static: true }) editorRef!: ElementRef;
private superdoc: SuperDoc | null = null;

ngOnInit() {
this.superdoc = new SuperDoc({
selector: this.editorElement.nativeElement,
document: 'contract.docx'
selector: this.editorRef.nativeElement,
document: 'contract.docx',
documentMode: 'editing',
});
}

ngOnDestroy() {
this.superdoc = null;
}

async exportDocument() {
if (this.superdoc) {
await this.superdoc.export();
}
this.superdoc?.destroy();
}
}
```

## With file input
## Full component

A reusable editor component with mode switching and export:

```typescript
import { Component, ElementRef, ViewChild, Input, OnInit, OnDestroy } from '@angular/core';
import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

@Component({
selector: 'app-editor',
selector: 'app-doc-editor',
template: `
<input type="file" accept=".docx" (change)="onFileSelected($event)">
<div #editor></div>
`
<div class="controls">
<button (click)="setMode('editing')">Edit</button>
<button (click)="setMode('suggesting')">Review</button>
<button (click)="setMode('viewing')">View</button>
<button (click)="exportDoc()">Export</button>
</div>
<div #editor style="height: 700px"></div>
`,
})
export class EditorComponent {
@ViewChild('editor', { static: false }) editorElement!: ElementRef;
export class DocEditorComponent implements OnInit, OnDestroy {
@ViewChild('editor', { static: true }) editorRef!: ElementRef;
@Input() document!: File | string;
@Input() user?: { name: string; email: string };

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
});
}
ngOnInit() {
this.superdoc = new SuperDoc({
selector: this.editorRef.nativeElement,
document: this.document,
documentMode: 'editing',
user: this.user,
onReady: () => console.log('Editor ready'),
});
}

ngOnDestroy() {
this.superdoc?.destroy();
}

setMode(mode: 'editing' | 'viewing' | 'suggesting') {
this.superdoc?.setDocumentMode(mode);
}

async exportDoc() {
await this.superdoc?.export({ isFinalDoc: true });
}
}
```

## Service pattern
## Handle file uploads

```typescript
@Injectable({ providedIn: 'root' })
export class DocumentService {
@Component({
selector: 'app-upload-editor',
template: `
<input type="file" accept=".docx" (change)="onFileChange($event)" />
<div #editor style="height: 700px"></div>
`,
})
export class UploadEditorComponent implements OnDestroy {
@ViewChild('editor', { static: true }) editorRef!: ElementRef;
private superdoc: SuperDoc | null = null;

initialize(element: HTMLElement, document: File | string) {
onFileChange(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (!file) return;

this.superdoc?.destroy();
this.superdoc = new SuperDoc({
selector: element,
document
selector: this.editorRef.nativeElement,
document: file,
documentMode: 'editing',
});
return this.superdoc;
}

destroy() {
this.superdoc = null;
ngOnDestroy() {
this.superdoc?.destroy();
}
}
```
```

## Next steps

- [Configuration](/core/superdoc/configuration) - Full configuration options
- [Methods](/core/superdoc/methods) - All available methods
- [Angular Example](https://github.com/superdoc-dev/superdoc/tree/main/examples/getting-started/angular) - Working example on GitHub
2 changes: 1 addition & 1 deletion examples/__tests__/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));

// EXAMPLE can be:
// "react", "vue", "vanilla", "cdn" (getting-started)
// "react", "vue", "vanilla", "cdn", "angular" (getting-started)
// "collaboration/superdoc-yjs", "collaboration/hocuspocus", etc.
const example = process.env.EXAMPLE || 'react';

Expand Down
2 changes: 2 additions & 0 deletions examples/getting-started/angular/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist
.angular
15 changes: 15 additions & 0 deletions examples/getting-started/angular/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SuperDoc — Angular

Minimal Angular example.

## Run

```bash
npm install
npm run dev
```

## Learn more

- [Angular Guide](https://docs.superdoc.dev/getting-started/frameworks/angular)
- [Configuration Reference](https://docs.superdoc.dev/core/superdoc/configuration)
41 changes: 41 additions & 0 deletions examples/getting-started/angular/angular.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": { "analytics": false },
"projects": {
"superdoc-angular-example": {
"projectType": "application",
"root": "",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.json",
"styles": ["src/styles.css"]
},
"configurations": {
"production": {
"budgets": [
{ "type": "initial", "maximumWarning": "5MB", "maximumError": "10MB" }
]
},
"development": {
"optimization": false,
"sourceMap": true
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"buildTarget": "superdoc-angular-example:build:development"
}
}
}
}
}
}
25 changes: 25 additions & 0 deletions examples/getting-started/angular/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "superdoc-angular-example",
"private": true,
"scripts": {
"dev": "ng serve",
"build": "ng build"
},
"dependencies": {
"@angular/common": "^21.1.4",
"@angular/compiler": "^21.1.4",
"@angular/core": "^21.1.4",
"@angular/platform-browser": "^21.1.4",
"@angular/platform-browser-dynamic": "^21.1.4",
"rxjs": "~7.8.2",
"superdoc": "latest",
"tslib": "^2.8.1",
"zone.js": "~0.16.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^21.1.4",
"@angular/cli": "^21.1.4",
"@angular/compiler-cli": "^21.1.4",
"typescript": "~5.9.3"
}
}
Empty file.
33 changes: 33 additions & 0 deletions examples/getting-started/angular/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Component, ElementRef, ViewChild, OnDestroy } from '@angular/core';
import { SuperDoc } from 'superdoc';

@Component({
selector: 'app-root',
template: `
<div style="padding: 1rem; background: #f5f5f5">
<input type="file" accept=".docx" (change)="onFileChange($event)" />
</div>
<div #editor style="height: calc(100vh - 60px)"></div>
`,
})
export class AppComponent implements OnDestroy {
@ViewChild('editor', { static: true }) editorRef!: ElementRef;

private superdoc: SuperDoc | null = null;

onFileChange(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
if (!file) return;

this.superdoc?.destroy();
this.superdoc = new SuperDoc({
selector: this.editorRef.nativeElement,
documentMode: 'editing',
document: file,
});
}

ngOnDestroy() {
this.superdoc?.destroy();
}
}
11 changes: 11 additions & 0 deletions examples/getting-started/angular/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SuperDoc — Angular</title>
</head>
<body>
<app-root></app-root>
</body>
</html>
4 changes: 4 additions & 0 deletions examples/getting-started/angular/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent);
1 change: 1 addition & 0 deletions examples/getting-started/angular/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'superdoc/style.css';
17 changes: 17 additions & 0 deletions examples/getting-started/angular/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true,
"isolatedModules": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"moduleResolution": "bundler",
"target": "ES2022",
"module": "ES2022"
},
"angularCompilerOptions": {
"strictTemplates": true
},
"files": ["src/main.ts"],
"include": ["src/**/*.ts"]
}
8 changes: 4 additions & 4 deletions packages/superdoc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"require": "./dist/superdoc.cjs"
},
"./types": {
"types": "./dist/types.d.ts",
"types": "./dist/super-editor/src/types.d.ts",
"source": "./src/types.ts",
"import": "./dist/types.es.js",
"require": "./dist/types.cjs"
Expand Down Expand Up @@ -52,7 +52,7 @@
"./dist/super-editor/src/index.d.ts"
],
"types": [
"./dist/types.d.ts"
"./dist/super-editor/src/types.d.ts"
]
}
},
Expand All @@ -62,10 +62,10 @@
"dev": "vite",
"dev:collab": "concurrently -k -n VITE,COLLAB -c cyan,green \"vite\" \"node src/dev/collab-server.js\"",
"collab-server": "node src/dev/collab-server.js",
"build": "pnpm --prefix ../super-editor run types:build && vite build && pnpm run build:umd",
"build": "vite build && pnpm run build:umd",
"build:dev": "SUPERDOC_SKIP_DTS=1 vite build",
"postbuild": "node ./scripts/ensure-types.cjs",
"build:es": "pnpm --prefix ../super-editor run types:build && vite build && node ./scripts/ensure-types.cjs",
"build:es": "vite build && node ./scripts/ensure-types.cjs",
"watch:es": "vite build --watch",
"build:umd": "vite build --config vite.config.umd.js",
"clean": "rm -rf dist",
Expand Down
Loading
Loading