|
| 1 | +# SuperDoc |
| 2 | + |
| 3 | +A document editing and rendering library for the web. |
| 4 | + |
| 5 | +## Architecture: Rendering |
| 6 | + |
| 7 | +SuperDoc uses its own rendering pipeline. ProseMirror stores document state; it is not the visual renderer. |
| 8 | + |
| 9 | +``` |
| 10 | +.docx |
| 11 | + → super-converter parses OOXML into the hidden PM doc |
| 12 | + → pm-adapter reads PM state and resolved styles |
| 13 | + → FlowBlock[] |
| 14 | + → layout-engine paginates |
| 15 | + → ResolvedLayout |
| 16 | + → DomPainter paints DOM |
| 17 | +``` |
| 18 | + |
| 19 | +- `PresentationEditor` wraps a hidden ProseMirror `Editor`. Its contenteditable DOM is never shown. PresentationEditor bridges editor events into layout/paint state; do not resolve OOXML semantics there. |
| 20 | +- **DomPainter** (`layout-engine/painters/dom/`) owns all visual rendering. |
| 21 | +- Style-resolved properties flow `pm-adapter` → DomPainter. Do not style document content with PM decorations. |
| 22 | + |
| 23 | +### Where To Put Your Change |
| 24 | + |
| 25 | +| Concern | Where | Rule | |
| 26 | +|---|---|---| |
| 27 | +| DOCX import/export | `super-editor/src/editors/v1/core/super-converter/` | Parse and preserve OOXML, style refs, inline properties. Do not bake resolved formatting into direct attrs. | |
| 28 | +| Style cascade | `layout-engine/style-engine/` | Single source of truth for defaults, styles, conditional formatting, inline overrides. | |
| 29 | +| Static document visuals | `pm-adapter/` data + `layout-engine/painters/dom/` rendering | Feed typed data into DomPainter. Do not style static content with PM decorations. | |
| 30 | +| Direction-aware properties | `layout-engine/painters/dom/` | DomPainter mirrors at paint time for `w:bidiVisual`. pm-adapter stores logical sides LTR-default. Pre-mirroring upstream is a double-swap. See `packages/layout-engine/pm-adapter/src/direction/README.md`. | |
| 31 | +| Editing behavior | `super-editor/src/editors/v1/extensions/` | Commands, keybindings, editor plugins. Do not duplicate cascade or render document visuals here. | |
| 32 | +| Final DOM rendering | `layout-engine/painters/dom/` | Render `ResolvedLayout`. Paint-time transforms (e.g. RTL mirror) live here. | |
| 33 | +| New doc-api operation | `packages/document-api/src/contract/operation-definitions.ts` | Contract-first; touches 4 files. See `packages/document-api/README.md`. | |
| 34 | + |
| 35 | +For specialized boundaries (interaction mapping, geometry/pagination, ephemeral overlays, presentation state bridge, consumer SDK surface), see `packages/layout-engine/AGENTS.md` and the relevant package AGENTS.md. |
| 36 | + |
| 37 | +### Boundary check |
| 38 | + |
| 39 | +Before adding a visual or direction-aware path, run: |
| 40 | + |
| 41 | +```bash |
| 42 | +# Painter must not import upstream packages. |
| 43 | +rg "@superdoc/(pm-adapter|style-engine|layout-bridge|layout-resolved)" packages/layout-engine/painters/dom/src |
| 44 | +``` |
| 45 | + |
| 46 | +More checks in `packages/layout-engine/AGENTS.md`. |
| 47 | + |
| 48 | +## Style Resolution Boundary |
| 49 | + |
| 50 | +The importer stores raw OOXML. The style-engine resolves at render time. |
| 51 | + |
| 52 | +- Converter (`super-converter/`) parses and stores only what is explicitly in the XML. |
| 53 | +- Style-engine (`layout-engine/style-engine/`) owns cascade logic. |
| 54 | + |
| 55 | +**Why**: resolving during import bakes inline properties into nodes; export then writes direct formatting instead of style references and loses document intent. |
| 56 | + |
| 57 | +## Document API Contract |
| 58 | + |
| 59 | +`packages/document-api/` uses a contract-first pattern. |
| 60 | + |
| 61 | +- **`operation-definitions.ts`** is the canonical object. All downstream maps project from it. |
| 62 | +- **`operation-registry.ts`** is the type-level registry (`input`, `options`, `output`). |
| 63 | +- **`invoke.ts`** is the dispatch table, validated against the registry at compile time. |
| 64 | + |
| 65 | +Adding an operation touches 4 files: `operation-definitions.ts`, `operation-registry.ts`, `invoke.ts`, and the implementation. Run `pnpm run generate:all` after. See `packages/document-api/README.md`. |
| 66 | + |
| 67 | +Do not hand-edit `COMMAND_CATALOG`, `OPERATION_MEMBER_PATH_MAP`, `OPERATION_REFERENCE_DOC_PATH_MAP`, or `REFERENCE_OPERATION_GROUPS`. They are derived from `OPERATION_DEFINITIONS`. |
| 68 | + |
| 69 | +## Commands |
| 70 | + |
| 71 | +- `pnpm build` - build all packages |
| 72 | +- `pnpm test` - unit tests |
| 73 | +- `pnpm dev` - dev server from `examples/` |
| 74 | +- `pnpm run generate:all` - regenerate schemas, SDK clients, tool catalogs, reference docs |
| 75 | + |
| 76 | +## Testing |
| 77 | + |
| 78 | +| What to verify | Command | Speed | |
| 79 | +|---|---|---| |
| 80 | +| Logic works? | `pnpm test` | seconds | |
| 81 | +| Editing works? | `pnpm test:behavior` | minutes | |
| 82 | +| Layout regressed? | `pnpm test:layout` | ~10 min | |
| 83 | +| Pixel diff? | `pnpm test:visual` | ~5 min | |
| 84 | + |
| 85 | +Per-package detail: `tests/behavior/AGENTS.md`, `tests/visual/AGENTS.md`. Eval suite: `evals/AGENTS.md`. |
0 commit comments