Skip to content

Commit 93459ff

Browse files
committed
fix: resolve published type declarations for Angular/TS consumers and add Angular example
1 parent 7371750 commit 93459ff

18 files changed

Lines changed: 306 additions & 116 deletions

File tree

CLAUDE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ tests/visual/ Visual regression tests (Playwright + R2 baselines)
8282
- **Editing commands/behavior**: Modify `super-editor/src/extensions/`
8383
- **State bridging**: Modify `PresentationEditor.ts`
8484

85+
## JSDoc types
86+
87+
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.
88+
89+
- **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.
90+
- **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/`.
91+
- **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.
92+
8593
## Commands
8694

8795
- `pnpm build` - Build all packages
Lines changed: 83 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,132 @@
11
---
2-
title: Angular
2+
title: Angular Integration
3+
sidebarTitle: Angular
34
keywords: "angular docx editor, angular word component, superdoc angular, angular document editor, angular integration"
45
---
56

6-
SuperDoc works with Angular through direct DOM manipulation.
7+
SuperDoc works with Angular through direct DOM manipulation. No wrapper needed.
78

8-
## Installation
9+
## Install
910

1011
```bash
1112
npm install superdoc
1213
```
1314

14-
## Basic component
15+
## Basic setup
1516

1617
```typescript
17-
import { Component, ElementRef, ViewChild, OnInit, OnDestroy } from '@angular/core';
18+
import { Component, ElementRef, ViewChild, OnDestroy } from '@angular/core';
1819
import { SuperDoc } from 'superdoc';
20+
import 'superdoc/style.css';
1921

2022
@Component({
21-
selector: 'app-document-editor',
22-
template: `
23-
<div #editor class="editor-container"></div>
24-
`,
25-
styles: [`
26-
.editor-container {
27-
height: 700px;
28-
}
29-
`]
23+
selector: 'app-editor',
24+
template: `<div #editor style="height: 700px"></div>`,
3025
})
31-
export class DocumentEditorComponent implements OnInit, OnDestroy {
32-
@ViewChild('editor', { static: true }) editorElement!: ElementRef;
26+
export class EditorComponent implements OnDestroy {
27+
@ViewChild('editor', { static: true }) editorRef!: ElementRef;
3328
private superdoc: SuperDoc | null = null;
3429

3530
ngOnInit() {
3631
this.superdoc = new SuperDoc({
37-
selector: this.editorElement.nativeElement,
38-
document: 'contract.docx'
32+
selector: this.editorRef.nativeElement,
33+
document: 'contract.docx',
34+
documentMode: 'editing',
3935
});
4036
}
4137

4238
ngOnDestroy() {
43-
this.superdoc = null;
44-
}
45-
46-
async exportDocument() {
47-
if (this.superdoc) {
48-
await this.superdoc.export();
49-
}
39+
this.superdoc?.destroy();
5040
}
5141
}
5242
```
5343

54-
## With file input
44+
## Full component
45+
46+
A reusable editor component with mode switching and export:
5547

5648
```typescript
49+
import { Component, ElementRef, ViewChild, Input, OnDestroy } from '@angular/core';
50+
import { SuperDoc } from 'superdoc';
51+
import 'superdoc/style.css';
52+
5753
@Component({
58-
selector: 'app-editor',
54+
selector: 'app-doc-editor',
5955
template: `
60-
<input type="file" accept=".docx" (change)="onFileSelected($event)">
61-
<div #editor></div>
62-
`
56+
<div class="controls">
57+
<button (click)="setMode('editing')">Edit</button>
58+
<button (click)="setMode('suggesting')">Review</button>
59+
<button (click)="setMode('viewing')">View</button>
60+
<button (click)="exportDoc()">Export</button>
61+
</div>
62+
<div #editor style="height: 700px"></div>
63+
`,
6364
})
64-
export class EditorComponent {
65-
@ViewChild('editor', { static: false }) editorElement!: ElementRef;
65+
export class DocEditorComponent implements OnDestroy {
66+
@ViewChild('editor', { static: true }) editorRef!: ElementRef;
67+
@Input() document!: File | string;
68+
@Input() user?: { name: string; email: string };
69+
6670
private superdoc: SuperDoc | null = null;
6771

68-
onFileSelected(event: Event) {
69-
const file = (event.target as HTMLInputElement).files?.[0];
70-
if (file && this.editorElement) {
71-
this.superdoc = new SuperDoc({
72-
selector: this.editorElement.nativeElement,
73-
document: file
74-
});
75-
}
72+
ngOnInit() {
73+
this.superdoc = new SuperDoc({
74+
selector: this.editorRef.nativeElement,
75+
document: this.document,
76+
documentMode: 'editing',
77+
user: this.user,
78+
onReady: () => console.log('Editor ready'),
79+
});
80+
}
81+
82+
ngOnDestroy() {
83+
this.superdoc?.destroy();
84+
}
85+
86+
setMode(mode: 'editing' | 'viewing' | 'suggesting') {
87+
this.superdoc?.setDocumentMode(mode);
88+
}
89+
90+
async exportDoc() {
91+
await this.superdoc?.export({ isFinalDoc: true });
7692
}
7793
}
7894
```
7995

80-
## Service pattern
96+
## Handle file uploads
8197

8298
```typescript
83-
@Injectable({ providedIn: 'root' })
84-
export class DocumentService {
99+
@Component({
100+
selector: 'app-upload-editor',
101+
template: `
102+
<input type="file" accept=".docx" (change)="onFileChange($event)" />
103+
<div #editor style="height: 700px"></div>
104+
`,
105+
})
106+
export class UploadEditorComponent implements OnDestroy {
107+
@ViewChild('editor', { static: true }) editorRef!: ElementRef;
85108
private superdoc: SuperDoc | null = null;
86109

87-
initialize(element: HTMLElement, document: File | string) {
110+
onFileChange(event: Event) {
111+
const file = (event.target as HTMLInputElement).files?.[0];
112+
if (!file) return;
113+
114+
this.superdoc?.destroy();
88115
this.superdoc = new SuperDoc({
89-
selector: element,
90-
document
116+
selector: this.editorRef.nativeElement,
117+
document: file,
118+
documentMode: 'editing',
91119
});
92-
return this.superdoc;
93120
}
94121

95-
destroy() {
96-
this.superdoc = null;
122+
ngOnDestroy() {
123+
this.superdoc?.destroy();
97124
}
98125
}
99-
```
126+
```
127+
128+
## Next steps
129+
130+
- [Configuration](/core/superdoc/configuration) - Full configuration options
131+
- [Methods](/core/superdoc/methods) - All available methods
132+
- [Angular Example](https://github.com/superdoc-dev/superdoc/tree/main/examples/getting-started/angular) - Working example on GitHub
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dist
2+
.angular
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SuperDoc — Angular
2+
3+
Minimal Angular example.
4+
5+
## Run
6+
7+
```bash
8+
npm install
9+
npm run dev
10+
```
11+
12+
## Learn more
13+
14+
- [Angular Guide](https://docs.superdoc.dev/getting-started/frameworks/angular)
15+
- [Configuration Reference](https://docs.superdoc.dev/core/superdoc/configuration)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3+
"version": 1,
4+
"cli": { "analytics": false },
5+
"projects": {
6+
"superdoc-angular-example": {
7+
"projectType": "application",
8+
"root": "",
9+
"architect": {
10+
"build": {
11+
"builder": "@angular-devkit/build-angular:application",
12+
"options": {
13+
"outputPath": "dist",
14+
"index": "src/index.html",
15+
"browser": "src/main.ts",
16+
"polyfills": ["zone.js"],
17+
"tsConfig": "tsconfig.json",
18+
"styles": ["src/styles.css"]
19+
},
20+
"configurations": {
21+
"production": {
22+
"budgets": [
23+
{ "type": "initial", "maximumWarning": "5MB", "maximumError": "10MB" }
24+
]
25+
},
26+
"development": {
27+
"optimization": false,
28+
"sourceMap": true
29+
}
30+
}
31+
},
32+
"serve": {
33+
"builder": "@angular-devkit/build-angular:dev-server",
34+
"options": {
35+
"buildTarget": "superdoc-angular-example:build:development"
36+
}
37+
}
38+
}
39+
}
40+
}
41+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "superdoc-angular-example",
3+
"private": true,
4+
"scripts": {
5+
"dev": "ng serve",
6+
"build": "ng build"
7+
},
8+
"dependencies": {
9+
"@angular/common": "^21.1.4",
10+
"@angular/compiler": "^21.1.4",
11+
"@angular/core": "^21.1.4",
12+
"@angular/platform-browser": "^21.1.4",
13+
"@angular/platform-browser-dynamic": "^21.1.4",
14+
"rxjs": "~7.8.2",
15+
"superdoc": "latest",
16+
"tslib": "^2.8.1",
17+
"zone.js": "~0.16.0"
18+
},
19+
"devDependencies": {
20+
"@angular-devkit/build-angular": "^21.1.4",
21+
"@angular/cli": "^21.1.4",
22+
"@angular/compiler-cli": "^21.1.4",
23+
"typescript": "~5.9.3"
24+
}
25+
}

examples/getting-started/angular/public/.gitkeep

Whitespace-only changes.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Component, ElementRef, ViewChild } from '@angular/core';
2+
import { SuperDoc } from 'superdoc';
3+
4+
@Component({
5+
selector: 'app-root',
6+
template: `
7+
<div style="padding: 1rem; background: #f5f5f5">
8+
<input type="file" accept=".docx" (change)="onFileChange($event)" />
9+
</div>
10+
<div #editor style="height: calc(100vh - 60px)"></div>
11+
`,
12+
})
13+
export class AppComponent {
14+
@ViewChild('editor', { static: true }) editorRef!: ElementRef;
15+
16+
private superdoc: SuperDoc | null = null;
17+
18+
onFileChange(event: Event) {
19+
const file = (event.target as HTMLInputElement).files?.[0];
20+
if (!file) return;
21+
22+
this.superdoc?.destroy();
23+
this.superdoc = new SuperDoc({
24+
selector: this.editorRef.nativeElement,
25+
documentMode: 'editing',
26+
document: file,
27+
});
28+
}
29+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>SuperDoc — Angular</title>
7+
</head>
8+
<body>
9+
<app-root></app-root>
10+
</body>
11+
</html>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { bootstrapApplication } from '@angular/platform-browser';
2+
import { AppComponent } from './app/app.component';
3+
4+
bootstrapApplication(AppComponent);

0 commit comments

Comments
 (0)