Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
7bad8f0
feat(superdoc): add layout-change event for responsive fit-to-contain…
mattConnHarbour May 28, 2026
f168de5
fix(superdoc): wait for layout ready before capturing base document w…
mattConnHarbour May 28, 2026
fd9f34b
test(superdoc): add tests for layout-change event
mattConnHarbour May 28, 2026
aefcb1a
chore(deps): bump uuid to ^11.1.1 (CVE-2026-41907)
mattConnHarbour Jun 3, 2026
f174110
feat(superdoc): zoom modes with viewport metrics and fit-width (SD-3294)
caio-pizzol Jun 5, 2026
ac41f85
feat(react): zoom and viewport callback props (SD-3294)
caio-pizzol Jun 5, 2026
e2c93be
docs(superdoc): zoom modes, viewport-change event, fit-width config (…
caio-pizzol Jun 5, 2026
6472895
feat(superdoc): observable zoom-mode transitions and format-aware vie…
caio-pizzol Jun 5, 2026
74d41d5
feat(ui): zoom domain, useSuperDocZoom, and zoom-fit-width command (S…
caio-pizzol Jun 5, 2026
62476fb
Merge remote-tracking branch 'upstream/main' into matthew/sd-3294-lay…
mattConnHarbour Jun 5, 2026
cbe8261
Merge remote-tracking branch 'origin/matthew/sd-3294-layout-change-ev…
caio-pizzol Jun 5, 2026
4ae1d4f
test(superdoc): cover pdf normalization, widest-page, and fit-width c…
caio-pizzol Jun 5, 2026
90b768d
chore: refresh host-event prose and export snapshots after base merge…
caio-pizzol Jun 5, 2026
4192222
chore: restore base-side bytes the merge format hook rewrote (SD-3294)
caio-pizzol Jun 5, 2026
96ab4f8
fix(superdoc): key viewport-change dedup on fit, not raw available wi…
caio-pizzol Jun 5, 2026
a58352c
fix(super-editor): preserve generated line breaks in DOCX export (SD-…
caio-pizzol Jun 4, 2026
480ea20
fix(super-editor): keep caret after replacing break-only list content…
caio-pizzol Jun 5, 2026
f9a7b8e
fix(super-editor): require PM-contiguity when coalescing search range…
caio-pizzol Jun 5, 2026
042762d
Merge branch 'main' into sd-3361
caio-pizzol Jun 5, 2026
d643fb9
fix(superdoc): blocker round for zoom modes from review (SD-3294)
caio-pizzol Jun 5, 2026
34077b0
fix(ui): zoom hygiene for mode-only emissions (SD-3294)
caio-pizzol Jun 5, 2026
3bd10f3
test(super-editor): cover executeSpanTextRewrite newline probe (SD-3278)
caio-pizzol Jun 5, 2026
8c0ef72
chore(deps): regenerate pnpm-lock.yaml from a clean checkout
caio-pizzol Jun 5, 2026
ded0f3f
chore(deps): drop @types/uuid (uuid@11 ships its own types)
caio-pizzol Jun 5, 2026
4e14994
test(superdoc): cover viewport fit zoom edges
caio-pizzol Jun 5, 2026
65c3d5b
Merge branch 'main' into sd-3361
caio-pizzol Jun 5, 2026
f260c69
fix(superdoc): land the always-latest metrics store the prior message…
caio-pizzol Jun 5, 2026
3b4d535
docs(superdoc): width-source wording reflects laid-out pages first (S…
caio-pizzol Jun 5, 2026
1f6e463
docs(superdoc): tighten fit-width zoom docs
caio-pizzol Jun 5, 2026
bf716fe
docs: update bundled font license notices
caio-pizzol Jun 5, 2026
09d00a6
test(superdoc): declare esModule interop on the async PdfViewer mock …
caio-pizzol Jun 5, 2026
1342203
docs: add responsive zoom example
caio-pizzol Jun 5, 2026
1d5e023
chore: fix registry sync
harbournick Jun 5, 2026
25928d7
chore: gate bundled font license metadata
caio-pizzol Jun 5, 2026
1938ebb
Merge pull request #3659 from superdoc-dev/caio/sd-3294-fit-to-contai…
caio-pizzol Jun 5, 2026
6b2f044
Merge branch 'main' into matthew/sd-3294-layout-change-event
caio-pizzol Jun 5, 2026
dedb0f6
Merge pull request #3548 from superdoc-dev/matthew/sd-3294-layout-cha…
caio-pizzol Jun 5, 2026
b1c3ee5
Merge pull request #3665 from superdoc-dev/caio-pizzol/font-license-n…
caio-pizzol Jun 5, 2026
e7c5bf3
Merge pull request #3615 from superdoc-dev/sd-3361
caio-pizzol Jun 5, 2026
7f1c984
Merge pull request #3630 from superdoc-dev/caio/sd-3278-docx-export-c…
caio-pizzol Jun 5, 2026
72b5eb2
Merge branch 'stable'
harbournick Jun 5, 2026
c249d35
Merge pull request #3667 from superdoc-dev/caio/sd-3294-responsive-zo…
caio-pizzol Jun 5, 2026
f625b8e
refactor(font-system): source substitution evidence from @docfonts/fa…
caio-pizzol Jun 5, 2026
6530315
fix: align layout column expectation
caio-pizzol Jun 5, 2026
8f90d4d
Merge pull request #3669 from superdoc-dev/caio-pizzol/docfonts-fallb…
caio-pizzol Jun 5, 2026
197d2dc
Merge remote-tracking branch 'origin/stable' into sync/stable-to-main…
github-actions[bot] Jun 6, 2026
a96e918
Merge pull request #3668 from superdoc-dev/caio-pizzol/sd-2629-column…
caio-pizzol Jun 6, 2026
4ce95e9
Merge pull request #3670 from superdoc-dev/sync/stable-to-main-202606…
caio-pizzol Jun 6, 2026
176bd7f
chore(font-system): upgrade @docfonts/fallbacks to 0.3.0
caio-pizzol Jun 6, 2026
5c7e0d1
Merge pull request #3671 from superdoc-dev/caio-pizzol/fallbacks-0.3-…
caio-pizzol Jun 6, 2026
e101be3
feat(font-system): attach docfonts verdict evidence to font reports
caio-pizzol Jun 6, 2026
8ade7db
Merge pull request #3672 from superdoc-dev/caio-pizzol/verdict-aware-…
caio-pizzol Jun 6, 2026
0b99d22
Merge remote-tracking branch 'origin/main' into merge/main-into-stabl…
github-actions[bot] Jun 6, 2026
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
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ Do not hand-edit `COMMAND_CATALOG`, `OPERATION_MEMBER_PATH_MAP`, `OPERATION_REFE
- `pnpm test` - unit tests
- `pnpm dev` - dev server from `examples/`
- `pnpm check:types` - raw TS compile across all referenced projects (`tsc -b tsconfig.references.json`). Does NOT run the public-interface chain. Legacy alias: `pnpm run type-check`.
- `pnpm check:public` - **canonical pre-merge command for typed public surfaces.** Validates both `superdoc` (tier discipline + jsdoc ratchet + ts-jsdoc hygiene + public-method fixture coverage + vite build + postbuild chain + consumer typecheck matrix + deep-type audit + package-shape + snapshots + classification closure) and Document API (contract parity + output staleness + examples + overview). ~5 min. Non-mutating. Combines `check:public:superdoc` + `check:public:docapi`.
- `pnpm check:public:superdoc` - SuperDoc public package surface only. Wraps twelve stages in cheap-to-expensive order: `contract-tiers-test`, `contract-tiers`, `jsdoc-ratchet`, `jsdoc-hygiene-ts-test`, `jsdoc-hygiene-ts`, `public-method-coverage`, `build`, `consumer-typecheck-matrix`, `deep-type-audit-supported-root`, `package-shape`, `export-snapshots`, `root-classification-closure`. Legacy alias: `pnpm run check:public-contract`.
- `pnpm check:public` - **canonical pre-merge command for typed public surfaces.** Validates both `superdoc` (tier discipline + jsdoc ratchet + ts-jsdoc hygiene + public-method fixture coverage + bundled font license gate + vite build + postbuild chain + consumer typecheck matrix + deep-type audit + package-shape + snapshots + classification closure + docs snippet typecheck) and Document API (contract parity + output staleness + examples + overview). ~5 min. Non-mutating. Combines `check:public:superdoc` + `check:public:docapi`.
- `pnpm check:public:superdoc` - SuperDoc public package surface only. Wraps fourteen stages in cheap-to-expensive order: `contract-tiers-test`, `contract-tiers`, `jsdoc-ratchet`, `jsdoc-hygiene-ts-test`, `jsdoc-hygiene-ts`, `public-method-coverage`, `font-license-gate`, `build`, `consumer-typecheck-matrix`, `deep-type-audit-supported-root`, `package-shape`, `export-snapshots`, `root-classification-closure`, `docs-snippet-typecheck`. Legacy alias: `pnpm run check:public-contract`.
- `pnpm check:public:docapi` - Document API public surface only. Wraps four stages: `contract-parity`, `contract-outputs`, `examples`, `overview-alignment`. Clean-checkout safe: gitignored generated artifacts are built in memory; tracked outputs (reference docs, overview block) are compared byte-for-byte. No mutation. Legacy alias: `pnpm run docapi:check`.
- `pnpm check:font-licenses` - validate bundled font legal metadata: every `shared/font-system/assets/*.woff2` has a manifest row, stable hash, matching runtime bundled-manifest entry, and required notices. Also runs inside `check:public:superdoc`.
- `pnpm generate:docapi` - regenerate Document API outputs after editing the contract (alias of `docapi:sync`). Writes gitignored Document API generated artifacts. Run only when you need the artifacts materialized locally (SDK builds, publishing); `check:public:docapi` does not require it.
- `pnpm generate:all` - regenerate schemas, SDK clients, tool catalogs, reference docs.
- `pnpm report:public:superdoc` - print public-contract tier metadata (supported / legacy / legacy-raw / asset / deprecated). Read-only, not a gate. Use `check:public:superdoc` (or its `contract-tiers` stage) to enforce. Source of truth: `packages/superdoc/scripts/type-surface.config.cjs`.
Expand Down
65 changes: 62 additions & 3 deletions THIRD_PARTY_LICENSES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,65 @@
# Third Party Licenses
# Third-Party Licenses

This project includes code from third-party libraries. Their licenses are listed below.
This file lists third-party components redistributed in SuperDoc and the license
terms that govern them.

---

## Bundled fonts

SuperDoc bundles open, metric-compatible substitute fonts so that documents
referencing a non-embedded Microsoft core font still render with correct line
breaks and pagination.

### Scope - applies to all delivery models

These font notices apply wherever SuperDoc distributes or serves the fonts:

- embedded or bundled within SuperDoc and its published packages;
- served to browsers as web fonts from a SuperDoc- or customer-operated host; and
- redistributed by a customer that embeds SuperDoc.

Web-font delivery is distribution under the SIL Open Font License, so these terms
are written to the broadest redistribution case and cover lighter delivery
models too. The authoritative per-family record and the full license texts ship
alongside the fonts at `shared/font-system/assets/` (`LICENSES.md`, `OFL.txt`,
`Apache-2.0.txt`). Distribute that notice set together with the font files.

SPDX license expression for this bundled font set: `OFL-1.1 AND Apache-2.0`.

### Components

| Family | Replaces | License | Reserved Font Name | Version |
| --- | --- | --- | --- | --- |
| Carlito | Calibri | OFL-1.1 | "Carlito" | 1.103 |
| Caladea | Cambria | Apache-2.0 | none | 1.002 |
| Liberation Sans | Arial | OFL-1.1 | none declared | 2.1.5 |
| Liberation Serif | Times New Roman | OFL-1.1 | none declared | 2.1.5 |
| Liberation Mono | Courier New | OFL-1.1 | none declared | 2.1.5 |

### Copyright & trademark notices from the font `name` tables

- **Carlito** (OFL-1.1): `Copyright (c) 2010-2013 by tyPoland Lukasz Dziedzic with Reserved Font Name "Carlito". Licensed under the SIL Open Font License, Version 1.1.` Carlito is a trademark of tyPoland Lukasz Dziedzic.
- **Caladea** (Apache-2.0): `Copyright (c) 2012 Huerta Tipografia`. Caladea is a trademark of Huerta Tipografia. No Reserved Font Name. No upstream `NOTICE` file.
- **Liberation Sans / Serif / Mono** (OFL-1.1): `Digitized data copyright (c) 2010 Google Corporation.` / `Copyright (c) 2012 Red Hat, Inc.` "Liberation" is a registered Red Hat trademark. The v2.1.5 files declare no OFL Reserved Font Name. SuperDoc names the unmodified fonts.

### Format conversion

The bundled faces are format-only TrueType-to-WOFF2 conversions (`fontTools`,
`flavor="woff2"`, Brotli; no subsetting; WOFF2 metadata omitted). No design,
metric, glyph, `cmap`, or `name`-table change. Verified for this ship set:
20 / 20 faces have a WOFF2 `name` table byte-identical to their source TTF with
identical glyph count and `cmap`, and all metrics are preserved. Under OFL FAQ
2.2.1 these are not Modified Versions and retain the original font names. For
Caladea, this also serves as the Apache-2.0 section 4(b) notice.

### License texts

- OFL-1.1: `shared/font-system/assets/OFL.txt`, with per-font copyright notices stacked at top.
- Apache-2.0: `shared/font-system/assets/Apache-2.0.txt`.

The fonts remain under their own OFL-1.1 / Apache-2.0 terms and are not
relicensed under SuperDoc's terms (AGPLv3 community build or commercial).

---

Expand All @@ -12,7 +71,7 @@ This project includes code from third-party libraries. Their licenses are listed

**License:** MIT

```
```text
The MIT License (MIT)

Copyright (c) 2015 Thomas Bluemel
Expand Down
1 change: 1 addition & 0 deletions apps/docs/advanced/headless-toolbar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ Snapshot values match the format you pass to `execute()`. What you read is what
| `redo` | — | — |
| `ruler` | — | — |
| `zoom` | number (e.g. `125`) | number |
| `zoom-fit-width` | none | none |
| `document-mode` | `'editing'` \| `'suggesting'` \| `'viewing'` | mode string |

### Track changes
Expand Down
13 changes: 13 additions & 0 deletions apps/docs/editor/custom-ui/api-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,19 @@ await ui.document.export({ exportType: ['docx'], commentsType: 'external', trigg
await ui.document.replaceFile(file);
```

### `ui.zoom`

Zoom state, viewport metrics, and the two mutations. The snapshot updates on value changes, mode-only transitions, and viewport metric updates.

```ts
ui.zoom.getSnapshot(); // { mode, value, fitZoom, min, max, metrics }
ui.zoom.observe((snapshot) => {});
ui.zoom.set(125); // numeric zoom; switches the host to manual mode
ui.zoom.setMode('fit-width'); // continuous fit to the available width
```

In React, `useSuperDocZoom()` returns the same snapshot plus bound `set` / `setMode` actions. The toolbar registry also exposes a `zoom-fit-width` toggle command for custom toolbars.

### `ui.selection`

Live slice, capture, restore, painted geometry.
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/editor/custom-ui/toolbar-and-commands.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Common ids you'll wire to buttons:
| Style | `linked-style`, `clear-formatting`, `copy-format` |
| History | `undo`, `redo` |
| Tracked changes | `track-changes-accept-selection`, `track-changes-reject-selection` |
| View | `ruler`, `zoom`, `document-mode` |
| View | `ruler`, `zoom`, `zoom-fit-width`, `document-mode` |
| Tables | `table-insert`, `table-add-row-before`, `table-add-row-after`, `table-delete-row`, `table-add-column-before`, `table-add-column-after`, `table-delete-column`, `table-merge-cells`, `table-split-cell`, `table-delete` |
| Insert | `image` |

Expand Down
90 changes: 90 additions & 0 deletions apps/docs/editor/superdoc/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,76 @@ new SuperDoc({
</CodeGroup>
</ParamField>

<ParamField path="zoom" type="Object">
Zoom behavior for the document. Use `mode: 'fit-width'` to keep DOCX and PDF documents fitted to the available container width. Calling `setZoom()` switches back to manual zoom.

<Expandable title="properties" defaultOpen>
<ParamField path="zoom.initial" type="number" default="100">
Initial zoom level as a percentage. In `fit-width` mode, this is the paint zoom until the first fit computes.
</ParamField>
<ParamField path="zoom.mode" type="'manual' | 'fit-width'" default="'manual'">
Starting zoom mode. `'manual'` holds the current value. `'fit-width'` keeps the document fitted to the container.
</ParamField>
<ParamField path="zoom.fitWidth" type="Object">
Bounds and padding for the applied fit-width zoom.
<Expandable title="properties">
<ParamField path="zoom.fitWidth.min" type="number" default="10">
Lower bound for the applied zoom percentage.
</ParamField>
<ParamField path="zoom.fitWidth.max" type="number" default="100">
Upper bound for the applied zoom percentage. The default never enlarges the document past its natural size; raise it to let wide containers scale the page up.
</ParamField>
<ParamField path="zoom.fitWidth.padding" type="number" default="0">
Horizontal padding in pixels reserved inside the available width before computing the fit.
</ParamField>
</Expandable>
</ParamField>
</Expandable>

For custom behavior, listen to [`viewport-change`](/editor/superdoc/events#viewport-change) and call `setZoom()` yourself.

<CodeGroup>

```javascript Usage
const superdoc = new SuperDoc({
selector: '#editor',
document: file,
zoom: {
mode: 'fit-width',
fitWidth: { min: 35, max: 100, padding: 24 },
},
});
```

```javascript Full Example
import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

const superdoc = new SuperDoc({
selector: '#editor',
document: yourFile,
zoom: {
initial: 100,
mode: 'fit-width',
fitWidth: { min: 35, max: 100, padding: 24 },
},
onZoomChange: ({ zoom, mode }) => {
console.log(`Zoom is now ${zoom}% (${mode})`);
},
});
```

</CodeGroup>

<Card
title="Responsive zoom example"
icon="code"
href="https://github.com/superdoc-dev/superdoc/tree/main/examples/editor/built-in-ui/responsive-zoom"
>
Minimal React example for fit-width zoom with current zoom and viewport metrics.
</Card>
</ParamField>

<ParamField path="layoutMode" type="string" deprecated>
<Warning>**Removed in v1.0**: Use `viewOptions.layout` instead. `'paginated'` → `'print'`, `'responsive'` → `'web'`.</Warning>
</ParamField>
Expand Down Expand Up @@ -684,6 +754,26 @@ All handlers are optional functions in the configuration:
```
</ParamField>

<ParamField path="onZoomChange" type="function">
Called when zoom changes from `setZoom()`, the toolbar zoom control, or `fit-width` mode.

```javascript
onZoomChange: ({ zoom, mode }) => {
setZoomIndicator(zoom, mode);
}
```
</ParamField>

<ParamField path="onViewportChange" type="function">
Called when the fit-width calculation changes. Pixel-level width jitter is deduped. `getViewportMetrics()` always reads the latest measurements.

```javascript
onViewportChange: ({ availableWidth, documentWidth, fitZoom }) => {
updateFitIndicator({ availableWidth, documentWidth, fitZoom });
}
```
</ParamField>

<ParamField path="onTrackedChangeBubbleAccept" type="function">
Custom handler for accepting tracked changes from comment bubbles. Replaces default accept behavior when provided.

Expand Down
43 changes: 38 additions & 5 deletions apps/docs/editor/superdoc/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -440,12 +440,12 @@ superdoc.on('pagination-update', ({ totalPages, superdoc }) => {

### `zoomChange`

When the zoom level changes via `setZoom()`.
When the zoom level changes, from any source: `setZoom()`, the toolbar zoom control, or [`fit-width` mode](/editor/superdoc/configuration#param-zoom). The payload carries the value and the mode that produced it. Also available as the `onZoomChange` config callback.

<CodeGroup>
```javascript Usage
superdoc.on('zoomChange', ({ zoom }) => {
console.log(`Zoom: ${zoom}%`);
superdoc.on('zoomChange', ({ zoom, mode }) => {
console.log(`Zoom: ${zoom}% (${mode})`);
});
```

Expand All @@ -458,8 +458,41 @@ const superdoc = new SuperDoc({
document: yourFile,
});

superdoc.on('zoomChange', ({ zoom }) => {
console.log(`Zoom: ${zoom}%`);
superdoc.on('zoomChange', ({ zoom, mode }) => {
console.log(`Zoom: ${zoom}% (${mode})`);
});
```
</CodeGroup>

### `viewport-change`

When the fit-width calculation changes. Pixel-level width changes that do not affect the rounded fit are deduped. `getViewportMetrics()` always reads the latest measurements.

- `availableWidth` - container width in pixels, minus the comments sidebar when visible
- `documentWidth` - the widest document page width in pixels at 100% zoom (zoom-independent; DOCX from laid-out pages with page-styles fallback, PDF from rendered pages)
- `fitZoom` - the unclamped zoom percentage that fits the page into the available width

HTML documents reflow to the container, so an HTML-only instance reports no metrics.

For most use cases, prefer [`zoom.mode: 'fit-width'`](/editor/superdoc/configuration#param-zoom). Subscribe to this event only when you want to apply custom zoom behavior.

<CodeGroup>
```javascript Usage
superdoc.on('viewport-change', ({ fitZoom }) => {
superdoc.setZoom(Math.min(100, Math.max(35, fitZoom)));
});
```

```javascript Full Example
import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

const superdoc = new SuperDoc({
selector: '#editor',
document: yourFile,
onViewportChange: ({ availableWidth, documentWidth, fitZoom }) => {
console.log(`Need ${fitZoom}% to fit ${documentWidth}px into ${availableWidth}px`);
},
});
```
</CodeGroup>
Expand Down
Loading
Loading