@reportwright/viewer 0.13.0 → 0.13.2-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.md +150 -7
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/dist/{chunk-L6YEIVVD.js → chunk-2KNQVFKW.js} +82 -55
- package/dist/{chunk-L6YEIVVD.js.map → chunk-2KNQVFKW.js.map} +2 -2
- package/dist/{chunk-DXHLIJEY.js → chunk-47ZAKRVN.js} +6 -6
- package/dist/chunk-CCH7CFU5.js +5026 -0
- package/dist/chunk-CCH7CFU5.js.map +6 -0
- package/dist/{chunk-YIX3OJXU.js → chunk-D7S5DL46.js} +4 -4
- package/dist/{chunk-CNDUJ7IV.js → chunk-DVJYE7HZ.js} +9 -6
- package/dist/chunk-DVJYE7HZ.js.map +6 -0
- package/dist/{chunk-BF7GCWZY.js → chunk-GOCWG6FG.js} +15 -15
- package/dist/{chunk-IFYCJZNS.js → chunk-GRYITZPG.js} +30 -30
- package/dist/{chunk-F5EPQTPF.js → chunk-H422SRD3.js} +29 -29
- package/dist/{chunk-FEM2QVOO.js → chunk-JD6EJ3LI.js} +4 -4
- package/dist/{chunk-QFLVVM3H.js → chunk-MS2LQC2O.js} +38 -28
- package/dist/chunk-MS2LQC2O.js.map +6 -0
- package/dist/{chunk-UHHURTSV.js → chunk-NARXO3DB.js} +7 -7
- package/dist/{chunk-TZXEEVKE.js → chunk-OED3YZYP.js} +90 -45
- package/dist/chunk-OED3YZYP.js.map +6 -0
- package/dist/{chunk-EK5CJY22.js → chunk-OMCWZYRI.js} +69 -39
- package/dist/chunk-OMCWZYRI.js.map +6 -0
- package/dist/{chunk-UJL7C2AS.js → chunk-U2ZY2NPQ.js} +4 -4
- package/dist/{chunk-PQNM6ET7.js → chunk-WOBRKNIA.js} +12 -12
- package/dist/designer.js +349 -147
- package/dist/designer.js.map +3 -3
- package/dist/engine.worker.bwip.js +4781 -0
- package/dist/engine.worker.bwip.js.map +6 -0
- package/dist/engine.worker.js +5675 -16781
- package/dist/engine.worker.js.map +3 -3
- package/dist/peer/{chunk-2CD5COHN.js → chunk-6KUUNDNN.js} +57 -30
- package/dist/peer/{chunk-2CD5COHN.js.map → chunk-6KUUNDNN.js.map} +1 -1
- package/dist/peer/{chunk-LWXQX3NJ.js → chunk-A6UXBSTP.js} +29 -29
- package/dist/peer/{chunk-V42KN7HD.js → chunk-CFTFTV2O.js} +6 -6
- package/dist/peer/{chunk-45GVDKP5.js → chunk-FN3FXACD.js} +7 -7
- package/dist/peer/chunk-ILBTPBOA.js +14226 -0
- package/dist/peer/chunk-ILBTPBOA.js.map +6 -0
- package/dist/peer/{chunk-VZHHNQYB.js → chunk-JQDW5OR3.js} +90 -45
- package/dist/peer/chunk-JQDW5OR3.js.map +6 -0
- package/dist/peer/chunk-JQTRDHQP.js +866 -0
- package/dist/peer/chunk-JQTRDHQP.js.map +6 -0
- package/dist/peer/chunk-KD6CDYGE.js +5024 -0
- package/dist/peer/chunk-KD6CDYGE.js.map +6 -0
- package/dist/peer/chunk-MXR6JBMP.js +546 -0
- package/dist/peer/chunk-MXR6JBMP.js.map +6 -0
- package/dist/peer/chunk-N42DCZZA.js +378 -0
- package/dist/peer/chunk-N42DCZZA.js.map +6 -0
- package/dist/peer/{chunk-MKY3SDXU.js → chunk-OUTKMWFM.js} +9 -6
- package/dist/peer/chunk-OUTKMWFM.js.map +6 -0
- package/dist/peer/{chunk-Z5II55QT.js → chunk-VJLMUGUI.js} +4 -4
- package/dist/peer/{chunk-3CBV5SAI.js → chunk-WABYQWMT.js} +12 -12
- package/dist/peer/{chunk-S6LSPHSU.js → chunk-XHCRHVRK.js} +4 -4
- package/dist/peer/{chunk-YITWGAR4.js → chunk-ZS3J4WBH.js} +30 -30
- package/dist/peer/designer.js +335 -134
- package/dist/peer/designer.js.map +3 -3
- package/dist/peer/engine.worker.bwip.js +4781 -0
- package/dist/peer/engine.worker.bwip.js.map +6 -0
- package/dist/peer/engine.worker.js +5675 -16781
- package/dist/peer/engine.worker.js.map +3 -3
- package/dist/peer/viewer.js +44 -12
- package/dist/peer/viewer.js.map +1 -1
- package/dist/viewer.d.ts +2 -0
- package/dist/viewer.js +44 -12
- package/dist/viewer.js.map +1 -1
- package/package.json +1 -2
- package/dist/chunk-CNDUJ7IV.js.map +0 -6
- package/dist/chunk-EK5CJY22.js.map +0 -6
- package/dist/chunk-QFLVVM3H.js.map +0 -6
- package/dist/chunk-TZXEEVKE.js.map +0 -6
- package/dist/peer/chunk-MKY3SDXU.js.map +0 -6
- package/dist/peer/chunk-VZHHNQYB.js.map +0 -6
- /package/dist/{chunk-DXHLIJEY.js.map → chunk-47ZAKRVN.js.map} +0 -0
- /package/dist/{chunk-FEM2QVOO.js.map → chunk-D7S5DL46.js.map} +0 -0
- /package/dist/{chunk-BF7GCWZY.js.map → chunk-GOCWG6FG.js.map} +0 -0
- /package/dist/{chunk-IFYCJZNS.js.map → chunk-GRYITZPG.js.map} +0 -0
- /package/dist/{chunk-F5EPQTPF.js.map → chunk-H422SRD3.js.map} +0 -0
- /package/dist/{chunk-YIX3OJXU.js.map → chunk-JD6EJ3LI.js.map} +0 -0
- /package/dist/{chunk-UHHURTSV.js.map → chunk-NARXO3DB.js.map} +0 -0
- /package/dist/{chunk-UJL7C2AS.js.map → chunk-U2ZY2NPQ.js.map} +0 -0
- /package/dist/{chunk-PQNM6ET7.js.map → chunk-WOBRKNIA.js.map} +0 -0
- /package/dist/peer/{chunk-LWXQX3NJ.js.map → chunk-A6UXBSTP.js.map} +0 -0
- /package/dist/peer/{chunk-V42KN7HD.js.map → chunk-CFTFTV2O.js.map} +0 -0
- /package/dist/peer/{chunk-45GVDKP5.js.map → chunk-FN3FXACD.js.map} +0 -0
- /package/dist/peer/{chunk-S6LSPHSU.js.map → chunk-VJLMUGUI.js.map} +0 -0
- /package/dist/peer/{chunk-3CBV5SAI.js.map → chunk-WABYQWMT.js.map} +0 -0
- /package/dist/peer/{chunk-Z5II55QT.js.map → chunk-XHCRHVRK.js.map} +0 -0
- /package/dist/peer/{chunk-YITWGAR4.js.map → chunk-ZS3J4WBH.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,59 @@
|
|
|
2
2
|
|
|
3
3
|
All `@reportwright/*` packages (formerly `@pagewrightjs/*`) share one version. The versioning policy is in [CONTRIBUTING.md](CONTRIBUTING.md#versioning-semver).
|
|
4
4
|
|
|
5
|
+
## 0.13.2-rc.1 — 2026-10-09 (release candidate)
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- **The rename to ReportWright is finished; every old Pagewright name keeps working until 1.0.** New names, with the old one kept as a deprecated alias:
|
|
9
|
+
- report schema: `reportwright/report@1` is now what new and saved reports carry; `pagewright/report@1` is read as the same format (a server before 0.9 cannot open a report saved by 0.13.2).
|
|
10
|
+
- HTTP headers: `x-reportwright-pages`, `-ms`, `-warnings`, `-snapshot`, `-pending`, `-signature` (webhooks and the audit SIEM webhook) and `-idempotency-key` (mail) are sent together with the old `x-pagewright-*` header; the proxy secret is read from `x-reportwright-proxy-secret`, else `x-pagewright-proxy-secret`.
|
|
11
|
+
- Prometheus metrics: `/api/v1/metrics` emits every family as `reportwright_*` and again as `pagewright_*` (the old ones go in 1.0: move dashboards and alerts). `scripts/uptime-check.mjs` reads either.
|
|
12
|
+
- one console warning per page for `definePagewrightElements`, the `<pagewright-viewer>` / `<pagewright-designer>` tags, the Svelte `pagewrightViewer` / `pagewrightDesigner` actions, `window.Pagewright` and `/embed/pagewright-viewer.js` (and `-viewer.full.js`). The React and Vue `PagewrightViewer` / `PagewrightDesigner` stay the same components, without a warning; all are typed `@deprecated`.
|
|
13
|
+
- the live demo moved to https://mrarun005.github.io/reportwright-demo/ (the site build's default base is `/reportwright-demo/`).
|
|
14
|
+
- kept as they are, since changing them would break stored data: the `.pw.json` extension, the designer clipboard format `pagewright/items@1`, and the salts of the TOTP secret key and the audit checkpoint chain.
|
|
15
|
+
- **The render worker is minified.** `engine.worker.js` (and `engine.worker.bwip.js`) in `@reportwright/viewer` and the embed builds are minified, still one file with no chunk imports, with a linked source map (`engine.worker.js.map`) beside it so worker stack traces stay readable. `engine.worker.js` 2,195,290 → 1,218,659 bytes (608 → 503 KB gzipped); `engine.worker.bwip.js` 1,651,602 → 973,261 bytes (315 → 267 KB gzipped). The size budget in tests/engine/b10-bundle-size.test.js is now 504 KB gzipped (was 600).
|
|
16
|
+
- **Publishing verifies before `latest` moves.** The publish workflow publishes to the `next` dist-tag, installs all nine packages from the registry and smoke-tests them (imports, PDF/XLSX/DOCX export, `qpdf --check`, `pw render`, the viewer's files, the wrappers' peer), and only then moves `latest`.
|
|
17
|
+
|
|
18
|
+
### Performance
|
|
19
|
+
- **Trade-off made by 0.13.1: less memory, about 10–14% slower.** The 0.13.1 fixes for grouped sorts (N44: sort runs spill to disk in smaller runs, about 8 MB) and for streamed tagged PDFs (N44: tagged structure flushed per page) cost time for the memory they save: about 10–14% slower on the tester's 2 vCPU machine (not measured here). Memory: a 200,000-row grouped ledger peaks at 232 MB instead of 280 MB, and the same with 50 runs (1,000,000 rows' run count) 240 MB instead of 296 MB; a tagged streamed PDF at 50k/100k/200k rows holds 6.7/7.3/9.3 MB off-heap instead of 16.8/29.1/36.6 MB. `spillSorter({ runMB, mergeMB })` sets the sort's run size if speed matters more than memory.
|
|
20
|
+
### Added
|
|
21
|
+
- **`pw import <folder>`: bulk import.** Every `.rdl`, `.rdlc`, `.jrxml`, `.rptdesign` and `.rdlx-json` report in a folder (`--recursive` for subfolders) is imported into `-o <outDir>`, which mirrors the folder.
|
|
22
|
+
- One bad file never stops the batch. Exit 0 means all were imported, 2 some failed, 1 none.
|
|
23
|
+
- Subreports, SSRS shared data sources (`.rds`), JasperReports style templates (`.jrtx`) and images are resolved across the batch. Images are copied once per content. Unresolved references are listed per file.
|
|
24
|
+
- `import-report.json` and a standalone, escaped `import-report.html` give for each file the mapped, approximated and dropped counts, each item's reason, and every expression that was not translated with its line and column.
|
|
25
|
+
- `.pw-import.json` holds the hash of each written file, and a re-run skips an output the user edited unless `--force`.
|
|
26
|
+
- `--verify` renders each report with its embedded or sample data and compares it with the output it replaced.
|
|
27
|
+
- Paths from the folder are untrusted. Links that point outside it are refused, outputs stay in `outDir`, and `--max-files` and `--max-bytes` cap the input.
|
|
28
|
+
- The importers now return structured `items` (each item's notes, untranslated expressions and source position) and take a `resolve` option for shared data sources and style templates.
|
|
29
|
+
- Docs: the CLI README, "Bulk import". Test: tests/engine/c132-import-batch.test.js.
|
|
30
|
+
- **`pw --version` / `pw -v`** prints the CLI version (from its package.json) and the version of the engine it carries.
|
|
31
|
+
- **`showWarnings`** (viewer option, default `false`): shows the render's warnings under the pages; the designer's Preview always shows them. Documented in the viewer README and typed in `ViewerOptions`.
|
|
32
|
+
- **ⓘ help tooltips in the designer.** Long help paragraphs (the Outline, Layers and Parts panels, field hints over 90 characters) sit behind an ⓘ button that opens on hover, keyboard focus or click and closes with Esc; the button is described by the text (`aria-describedby`).
|
|
33
|
+
### Fixed
|
|
34
|
+
- **An unchecked check box has no tick on the designer canvas.** The canvas drew ✓ in every check box; it now follows the value as the renderer does (`false`, `=False`, a missing value: empty), and dims the tick of a value only the data decides.
|
|
35
|
+
- **Selecting an item no longer moves the canvas.** The canvas toolbar grew a second row (24 px) when the align buttons of a selection appeared; it now has one fixed height (it scrolls sideways when narrow) and its hint moved to the status bar.
|
|
36
|
+
- **Keyboard nudge steps.** Arrow moves the selection 1 pt, or one grid step with Snap to grid on (a cell in cell mode); Shift+Arrow moves ten of them (it was 4 grid steps); positions stay rounded to 2 decimals.
|
|
37
|
+
- **Render warnings in the viewer read as words.** The count says "8 warnings" or "1 warning", not "warning(s)".
|
|
38
|
+
- **The Data panel lists a data set's fields when it declares none.** It said "No fields" next to 300 rows; it now detects them from inline JSON or the first rows of fetched data with the engine's own detection (`detectFields`, the one streaming uses) and marks them as detected.
|
|
39
|
+
- **No cut-off text in the Inspector and the Outline.** The Regional "Division by zero" choice gets the full width ("Infinity (as SSRS)" was cut); a long name in the Outline wraps inside the panel, with the full name as its tooltip, and the item type and buttons move under it together.
|
|
40
|
+
- **The parameter dialog's help matches the viewer.** The live-parameters option no longer says that turning it off adds a View report button (the button is always there), and the panel-columns help says the grid applies on a wide screen.
|
|
41
|
+
- **Export options icon.** The sun-like gear is a sliders icon; the button keeps its name, Export options.
|
|
42
|
+
|
|
43
|
+
## 0.13.1 — 2026-10-09
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- **N10: the CJK fonts are named Regular in the PDF.** `@reportwright/fonts-cjk` downloads variable TrueType fonts whose default instance is Thin; 0.13.0 cut and renamed the subset at Regular, but `exportPdf` and `exportPdfStream` built the BaseFont from the full font's PostScript name, so pdffonts showed `NotoSansJP-Thin` / `NotoSansKR-Thin`. Both now take the name from the subset they embed (`NotoSansJP-Regular`). Test: tests/engine/b11-cjk-names.test.js (the downloaded fonts are tested when present).
|
|
47
|
+
- **N44: a streamed tagged PDF's memory stays flat.** The writer kept where each object is in arrays of 7 bytes an object that doubled; a tagged million-row ledger has 8–11 million objects (an element per cell), most of tagging's ~125 MB at 1M rows. They are now blocks of 16,384 entries, each deflated (~2 KB) once the numbers are two blocks past; the tagger lets go of a page's elements when it ends. Same file byte for byte (but its ID): veraPDF UA-1 and A-2a pass, same `pdfinfo -struct` tree. Off-heap peak at 50k/100k/200k rows: 16.8/29.1/36.6 MB before, 6.7/7.3/9.3 MB after (RSS ~205 MB either way). Test: tests/engine/b11-n44-tagged-memory.test.js.
|
|
48
|
+
- **N45: `pw render` stopped by a signal leaves no temporary file.** SIGTERM (Docker, Kubernetes, CI), SIGINT (Ctrl+C) and SIGHUP remove `<file>.<pid>.part`, keep an older PDF at the path as it was, and exit 143, 130 or 129. Before, every one of them left the `.part` file. Test: tests/engine/b10-perf-cli.test.js.
|
|
49
|
+
- **N41: a copied worker starts.** The npm package's `engine.worker.js` bundles its libraries (bidi-js, fontkit) instead of importing them by name, so an esbuild app that copies it next to its bundle renders in the worker (it crashed with "Failed to resolve module specifier bidi-js" and fell back to the main thread). Barcodes and the standard-font metrics are files next to it (`engine.worker.bwip.js`, `engine.worker.stdfonts.js`), as in the browser build; the README says to copy `engine.worker*.js`. Test: tests/e2e/b11-esbuild-worker.mjs.
|
|
50
|
+
- **N40: `fonts` is optional.** `render()`, `exportPdf()`, `exportPdfStream()` and the Word, Excel and PowerPoint exports use one default store over `@reportwright/fonts` when given none, and an export loads the fonts the model uses into whatever store it gets, so render and export need not share a store (it failed with "this.loader is not a function" or 'Font "Helvetica" is not loaded'). A report in the standard PDF fonts needs no store and no fonts package (a bold title in a Helvetica report no longer loads Inter-Bold); a font that cannot load says "Install @reportwright/fonts, or pass { fontStore }". Test: tests/engine/b11-fonts-n40.test.js, and the packed packages in all four combinations (packages.test.js).
|
|
51
|
+
- **N19: one warning prefix.** The engine package's console warnings and deprecations start with `[reportwright]`, as the rest do (they said `[@reportwright/engine]`).
|
|
52
|
+
- **N43: the standard-font metrics are a table.** Helvetica, Times, Courier, Symbol and ZapfDingbats widths and font-wide metrics are generated once from the Adobe AFM data (`scripts/gen-standard-metrics.mjs` → `src/engine/text/standard-metrics.js`, 22 KB, 5 KB gzipped) instead of decompressed with pako from `@pdf-lib/standard-fonts` at every cold start; that package is no longer a dependency of `@reportwright/engine` or `@reportwright/viewer` (pdf-lib still installs it for itself), and the viewer's `engine.worker.stdfonts.js` is gone (the table is in the worker: 588 → 594 KB gzipped, about 100 KB gzipped less in all). PDFs are byte-identical. A new process making a 1-page Helvetica invoice: median of 10, 115 → 94 ms on an M2 (Node 20). Test: tests/engine/b11-fonts-n43.test.js.
|
|
53
|
+
- **N42: the designer Outline passes axe.** It was a `listbox` whose rows also hold their move buttons (a listbox may hold only options: aria-required-children, critical). The rows are now toggle buttons (`aria-pressed`) in a labelled group, with the same keyboard: one Tab stop, Up/Down/Home/End, Enter or Space selects.
|
|
54
|
+
- **N44: a large sort's memory stays flat.** The disk spill behind grouped and sorted streamed reports held a 1,000-row batch from every sorted run while merging (50 runs at 1,000,000 rows), so its memory grew with the rows. Runs are now about 8 MB (at most 10,000 rows), batches 200 rows, and the merge holds about 4 MB: past that many runs, groups of runs are merged on disk first. A 200,000-row grouped ledger: 280 → 232 MB peak; the same with 50 runs (the run count of 1,000,000 rows): 296 → 240 MB. `spillSorter({ runMB, mergeMB })` sets them. The engine README recommends `presorted: true` with ORDER BY at the source for big grouped reports. Test: tests/engine/b11-mem-spill.test.js.
|
|
55
|
+
- **SILENT-6: an item taller than the page warns in `validate()`.** A body item taller than the room the page has for the body (the page less its margins, page header and footer, a body section's own page and bands counted) warns with both heights and what the render does: its lower part is cut at the page bottom (a text box's text of more than one line continues on the next page). Tables, matrices, lists and subreports, which split by their rows, and pageless pages are quiet. `render()` keeps its own warning where it cuts (with the page number) and does not repeat validate's. Test: tests/engine/b11-mem-silent6-tall.test.js.
|
|
56
|
+
- **N37: repeated copies cascade.** Ctrl+D (Duplicate) and Paste put a copy 12 pt right and down, and 12 more while an item already sits there, so copying the same item again and again fans the copies out instead of stacking them on the first copy. A pasted coordinate that is not a finite number starts at 0, and the steps are bounded, so a paste of hostile JSON (`1e309`, 2^60) cannot hang the tab. Test: tests/engine/b11-mem-designer-cascade.test.js.
|
|
57
|
+
|
|
5
58
|
## 0.13.0 — 2026-10-09
|
|
6
59
|
|
|
7
60
|
A minor release: new options (`largeReportRows`, `signal`, `warnOnLeave`, `onDirtyChange`), the 14 standard PDF fonts, streamed Excel and Word exports, and warnings where mistakes used to be silent. The tester's 0.12.1 tickets are fixed except where noted; fonts are still TTF (WOFF2 is not done).
|
package/README.md
CHANGED
|
@@ -1,9 +1,136 @@
|
|
|
1
1
|
# @reportwright/viewer
|
|
2
2
|
|
|
3
|
+
An embeddable report viewer and drag-and-drop report designer for any web page: view, page, search, drill down and export PDF, Excel, Word, PowerPoint, HTML or CSV in the browser.
|
|
4
|
+
|
|
3
5
|
[](https://www.npmjs.com/package/@reportwright/viewer) [](https://github.com/MrArun005/reportwright/blob/main/LICENSE) [](https://socket.dev/npm/package/@reportwright/viewer)
|
|
4
6
|
|
|
7
|
+
**Live demo:** [mrarun005.github.io/reportwright-demo](https://mrarun005.github.io/reportwright-demo): the [gallery](https://mrarun005.github.io/reportwright-demo/#gallery) is this viewer, the [designer playground](https://mrarun005.github.io/reportwright-demo/play.html) is `mountDesigner` with your own pasted JSON or CSV, and [made by hand in the designer](https://mrarun005.github.io/reportwright-demo/learn.html) walks through building reports step by step.
|
|
8
|
+
|
|
5
9
|
The ReportWright report viewer in any web app (React is bundled inside, in a shadow root, so your styles do not leak in). A React app imports `@reportwright/viewer/react-peer` (and `/react-peer/designer`) instead, the same viewer using the app's own React, so the page loads React once; `@reportwright/react` does this for you:
|
|
6
10
|
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i @reportwright/viewer @reportwright/fonts
|
|
15
|
+
cp -r node_modules/@reportwright/fonts/public public/pw # serve fonts/, harfbuzz-subset.wasm, icc/ as static files
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
React and React DOM 18+ are peer dependencies (the default build carries its own copy inside the shadow root; `/react-peer` uses yours).
|
|
19
|
+
|
|
20
|
+
## Quick start (30 seconds, plain HTML + a bundler)
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<!-- index.html -->
|
|
24
|
+
<div id="report" style="height: 600px"></div>
|
|
25
|
+
<button id="save-pdf">Save PDF</button>
|
|
26
|
+
<script type="module" src="./main.js"></script>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
// main.js
|
|
31
|
+
import { mountViewer } from '@reportwright/viewer';
|
|
32
|
+
import definition from './orders.pw.json'; // the report from @reportwright/engine's README examples
|
|
33
|
+
|
|
34
|
+
const viewer = mountViewer('#report', {
|
|
35
|
+
definition,
|
|
36
|
+
data: { orders: { rows: [{ customer: 'Asha Rao', amount: 1200.5 }, { customer: 'Ben Ode', amount: 80 }] } },
|
|
37
|
+
fontsUrl: '/pw/fonts/',
|
|
38
|
+
});
|
|
39
|
+
viewer.on('ready', ({ pages }) => console.log(`${pages} page(s)`));
|
|
40
|
+
document.querySelector('#save-pdf').onclick = async () => open(URL.createObjectURL(await viewer.export('pdf')));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Run it with `npx vite` (Vite 7: set `worker: { format: 'es' }`, see below). Verified against this version in Chromium
|
|
44
|
+
with Vite 7.
|
|
45
|
+
|
|
46
|
+
## Examples
|
|
47
|
+
|
|
48
|
+
**Embed the designer and keep the definition in your app.**
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import { mountDesigner } from '@reportwright/viewer/designer';
|
|
52
|
+
const designer = mountDesigner('#designer', {
|
|
53
|
+
definition,
|
|
54
|
+
fontsUrl: '/pw/fonts/',
|
|
55
|
+
onSave: (def) => fetch('/api/reports/orders', { method: 'PUT', body: JSON.stringify(def) }),
|
|
56
|
+
toolbox: { hide: ['map'] },
|
|
57
|
+
});
|
|
58
|
+
designer.isDirty(); // unsaved changes?
|
|
59
|
+
designer.getDefinition(); // the current definition
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Re-run with new parameters without remounting.**
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
viewer.setParameters({ minAmount: 100 });
|
|
66
|
+
viewer.on('parameters', (p) => history.replaceState(null, '', '?' + new URLSearchParams(p)));
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Trim the toolbar and show render warnings while developing.**
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
mountViewer('#report', { definition, data, fontsUrl: '/pw/fonts/', toolbar: { hide: ['powerpoint', 'csv', 'sidebar'] }, showWarnings: true });
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**React, Vue, Svelte, Angular:** use [`@reportwright/react`](https://github.com/MrArun005/reportwright/tree/main/packages/react), [`@reportwright/vue`](https://github.com/MrArun005/reportwright/tree/main/packages/vue),
|
|
76
|
+
[`@reportwright/svelte`](https://github.com/MrArun005/reportwright/tree/main/packages/svelte) or [`@reportwright/angular`](https://github.com/MrArun005/reportwright/tree/main/packages/angular); they take the same options.
|
|
77
|
+
|
|
78
|
+
## Features
|
|
79
|
+
|
|
80
|
+
| Area | Viewer | Designer |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| Navigation | pages, thumbnails, document map, search, zoom, single / continuous / galley view | live preview |
|
|
83
|
+
| Interactivity | parameters, interactive sort, drill-down, drill-through (`onDrill`, `reports`) | data panel, inspector, toolbox (each can be hidden) |
|
|
84
|
+
| Export in the browser | PDF, PDF/A, Excel, Word, PowerPoint, HTML, CSV, JSON; print | the same, from the preview |
|
|
85
|
+
| Embedding | shadow root (no style leaks), CSP without `'unsafe-inline'`, `nonce` | `onSave`, `onOpen`, `readOnly`, `dataSourceTemplates`, `warnOnLeave` |
|
|
86
|
+
| Performance | rendering in a Web Worker; fonts fetched only when the layout needs them | |
|
|
87
|
+
|
|
88
|
+
## Options reference
|
|
89
|
+
|
|
90
|
+
From `dist/viewer.d.ts` and `dist/designer.d.ts`.
|
|
91
|
+
|
|
92
|
+
**`mountViewer(target, options)`** → `ViewerHandle`
|
|
93
|
+
|
|
94
|
+
| Option | Type | Meaning |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `definition` | object | the report JSON |
|
|
97
|
+
| `data` | `Record<string, unknown>` | JSON by data source name (a definition with one source also takes the JSON itself) |
|
|
98
|
+
| `fontsUrl` | string | URL of the served copy of `@reportwright/fonts/public/fonts` |
|
|
99
|
+
| `server`, `report`, `params` | string, string, object | a self-hosted server, a saved report id and its parameters |
|
|
100
|
+
| `reports` | `Record<string, object>` | definitions by id for drill-through and subreports without a server |
|
|
101
|
+
| `lang`, `title`, `height` | string | interface language, document title, element height |
|
|
102
|
+
| `toolbar` | `{ hide?, add? }` | hide built-in items, add buttons (`{ id, label, title?, after?, onClick(api) }`) |
|
|
103
|
+
| `viewMode` | `'single' \| 'continuous' \| 'galley'` | page layout on screen |
|
|
104
|
+
| `showWarnings` | boolean | list the render's warnings under the pages |
|
|
105
|
+
| `onReady` | `(error \| null) => void` | the first run ended |
|
|
106
|
+
| `onDrill` | `(report, params) => void` | handle a drill-through yourself |
|
|
107
|
+
| `fonts`, `customFonts`, `uiFontCss` | | extra report fonts and the interface font |
|
|
108
|
+
| `snapshot` | object | show a stored run |
|
|
109
|
+
| `allowHosts`, `unsafeFetch`, `fetch` | | data request guard (see below) |
|
|
110
|
+
| `nonce` | string | for the fallback `<style>` under a CSP |
|
|
111
|
+
|
|
112
|
+
**`mountDesigner(target, options)`** → `DesignerHandle` (`unmount`, `getDefinition`, `save`, `isDirty`): `server`,
|
|
113
|
+
`fontsUrl`, `report`, `definition`, `lang`, `height`, `onSave`, `onOpen`, `readOnly`, `toolbox: { hide }`,
|
|
114
|
+
`panels: { data, inspector }`, `dataSourceTemplates`, `nonce`, `allowHosts`, `unsafeFetch`, `fetch`, `warnOnLeave`
|
|
115
|
+
(default `true`), `onDirtyChange`.
|
|
116
|
+
|
|
117
|
+
## Browser support and limits
|
|
118
|
+
|
|
119
|
+
- Modern evergreen browsers with ES modules, Web Workers and constructable stylesheets (an older browser without the
|
|
120
|
+
last gets a `<style>` element). Node 20.9+ for the build tooling (`engines`).
|
|
121
|
+
- Without the worker (a bundler that does not copy it) the report renders on the main thread: it works, but large
|
|
122
|
+
reports make the page janky.
|
|
123
|
+
- Sorted or grouped exports in the browser hold every row in memory (about 1.3 KB a row measured): keep them under
|
|
124
|
+
about 100,000 rows, or render on the server with [`@reportwright/engine`](https://github.com/MrArun005/reportwright/tree/main/packages/engine).
|
|
125
|
+
- A browser cannot resolve DNS, so the private-address guard cannot catch a public name that points at a private
|
|
126
|
+
address (see [Data sources and private addresses](#data-sources-and-private-addresses)).
|
|
127
|
+
|
|
128
|
+
## Related packages
|
|
129
|
+
|
|
130
|
+
[`@reportwright/engine`](https://github.com/MrArun005/reportwright/tree/main/packages/engine) (the same rendering in Node), [`@reportwright/fonts`](https://github.com/MrArun005/reportwright/tree/main/packages/fonts) (required),
|
|
131
|
+
[`@reportwright/fonts-cjk`](https://github.com/MrArun005/reportwright/tree/main/packages/fonts-cjk), [`@reportwright/cli`](https://github.com/MrArun005/reportwright/tree/main/packages/cli), and the wrappers
|
|
132
|
+
[`react`](https://github.com/MrArun005/reportwright/tree/main/packages/react), [`vue`](https://github.com/MrArun005/reportwright/tree/main/packages/vue), [`svelte`](https://github.com/MrArun005/reportwright/tree/main/packages/svelte), [`angular`](https://github.com/MrArun005/reportwright/tree/main/packages/angular).
|
|
133
|
+
|
|
7
134
|
## Bundler setup (read this first)
|
|
8
135
|
|
|
9
136
|
The viewer renders in a Web Worker (`engine.worker.js`, one self-contained file next to the viewer). Bundlers that understand
|
|
@@ -11,8 +138,10 @@ The viewer renders in a Web Worker (`engine.worker.js`, one self-contained file
|
|
|
11
138
|
|
|
12
139
|
- **Vite 7**: set `worker: { format: 'es' }` in `vite.config.js`. Without it the build fails with
|
|
13
140
|
`Invalid value "iife" for option "worker.format"`.
|
|
14
|
-
- **esbuild** (plain bundling) does not follow `new Worker(new URL(...))`: copy
|
|
15
|
-
|
|
141
|
+
- **esbuild** (plain bundling) does not follow `new Worker(new URL(...))`: copy the worker files next to your bundle:
|
|
142
|
+
`cp node_modules/@reportwright/viewer/dist/engine.worker*.js dist/`. `engine.worker.js` has no imports (its libraries are
|
|
143
|
+
inside it); `engine.worker.bwip.js` (barcodes) loads only when a report
|
|
144
|
+
needs it. Without it those reports render on the main thread, with the warning below.
|
|
16
145
|
|
|
17
146
|
If the worker cannot load, the viewer still renders, on the main thread (slow and janky at 100k rows), and logs once
|
|
18
147
|
`[reportwright] worker did not load (<reason>); rendering on the main thread`. `handle.usesWorker` tells you which one you got.
|
|
@@ -136,11 +265,11 @@ Types are included (`ViewerOptions`, `DesignerOptions`, …). Framework wrappers
|
|
|
136
265
|
|
|
137
266
|
### Viewer toolbar: `toolbar.hide`
|
|
138
267
|
|
|
139
|
-
`toolbar: { hide: [...], add: [...] }` hides built-in items. A group key hides the whole group; an item id hides that one item. Hiding every export format also hides the Export menu and its options
|
|
268
|
+
`toolbar: { hide: [...], add: [...] }` hides built-in items. A group key hides the whole group; an item id hides that one item. Hiding every export format also hides the Export menu and its Export options button.
|
|
140
269
|
|
|
141
270
|
| Key | Hides |
|
|
142
271
|
|---|---|
|
|
143
|
-
| `export` | the Export menu: every format and the options
|
|
272
|
+
| `export` | the Export menu: every format and the Export options button (Print stays) |
|
|
144
273
|
| `pdf`, `excel`, `word`, `powerpoint`, `html`, `csv`, `json` | that one export format |
|
|
145
274
|
| `print` | the Print button |
|
|
146
275
|
| `search` | the search box and its match controls |
|
|
@@ -149,10 +278,18 @@ Types are included (`ViewerOptions`, `DesignerOptions`, …). Framework wrappers
|
|
|
149
278
|
| `sidebar` | the page thumbnails and the document map buttons |
|
|
150
279
|
| `parameters` | the Parameters button |
|
|
151
280
|
| `run`, `viewMode`, `fullScreen`, `stats` | those single items (use their id) |
|
|
152
|
-
| `exportOptions` | the options
|
|
281
|
+
| `exportOptions` | the Export options button (the formats stay) |
|
|
153
282
|
|
|
154
283
|
Any other key is taken as an item id. Unknown keys hide nothing.
|
|
155
284
|
|
|
285
|
+
### Render warnings: `showWarnings`
|
|
286
|
+
|
|
287
|
+
`showWarnings: true` shows the render's warnings (a data value that does not read as a number, an unknown field, content cut off at the page edge…) under the pages, as a collapsed list headed "8 warnings" or "1 warning". The default is `false`: readers of a finished report do not see them. The designer's Preview always shows them.
|
|
288
|
+
|
|
289
|
+
```js
|
|
290
|
+
mountViewer('#report', { definition, data, fontsUrl: '/fonts/', showWarnings: true });
|
|
291
|
+
```
|
|
292
|
+
|
|
156
293
|
### Controlling a mounted viewer: `ViewerHandle`
|
|
157
294
|
|
|
158
295
|
`mountViewer` returns a handle (the React, Vue, Svelte and Angular wrappers give you the same one through their ready callback or event):
|
|
@@ -165,15 +302,21 @@ Any other key is taken as an item id. Unknown keys hide nothing.
|
|
|
165
302
|
| `getPageCount()` | the page count of the last run (0 before the first) |
|
|
166
303
|
| `print()` | opens the print dialog for the PDF |
|
|
167
304
|
| `export(format)` | `Promise<Blob>`: `format` is `pdf`, `xlsx`, `docx`, `pptx`, `html`, `csv` or `json` (or the item ids `excel`, `word`, `powerpoint`) |
|
|
168
|
-
| `on(event, fn)` | listens for `ready` (a run finished, detail:
|
|
305
|
+
| `on(event, fn)` | listens for `ready` (a run finished, detail: `{ pages }`), `error` (detail: message), `page` (detail: current page), `parameters` (detail: the parameters); returns an unsubscribe function |
|
|
169
306
|
| `unmount()` | removes the viewer |
|
|
170
307
|
|
|
171
308
|
```js
|
|
172
309
|
const viewer = mountViewer('#report', { server, report: 'loan-statement' });
|
|
173
310
|
viewer.setParameters({ accountId: 'LN-2' }); // re-runs; 'ready' fires when it is done
|
|
174
|
-
|
|
311
|
+
document.querySelector('#save-pdf').onclick = async () => {
|
|
312
|
+
const pdf = await viewer.export('pdf'); // a Blob of the report as shown
|
|
313
|
+
open(URL.createObjectURL(pdf));
|
|
314
|
+
};
|
|
175
315
|
```
|
|
176
316
|
|
|
317
|
+
`export()` exports the last finished run. `ready` fires once that run is on screen, so calling `export()` inside a
|
|
318
|
+
`ready` listener (or `onReady`) works.
|
|
319
|
+
|
|
177
320
|
## Size
|
|
178
321
|
|
|
179
322
|
What a page downloads when the viewer mounts: **847 KB gzipped** (0.7.3: 877 KB), readable unminified code with
|
package/THIRD-PARTY-NOTICES.md
CHANGED
|
@@ -9,7 +9,7 @@ ReportWright is MIT licensed (see LICENSE). It ships or bundles the following th
|
|
|
9
9
|
| [HarfBuzz](https://github.com/harfbuzz/harfbuzz), compiled to WebAssembly by [harfbuzzjs](https://github.com/harfbuzz/harfbuzzjs) | harfbuzzjs 1.6.2 | HarfBuzz: "Old MIT" (below); harfbuzzjs: MIT, Copyright (c) 2019-2026 The harfbuzzjs project authors | text shaping (`harfbuzz.wasm`) and font subsetting (`harfbuzz-subset.wasm`) |
|
|
10
10
|
| [pdf-lib](https://github.com/Hopding/pdf-lib) | 1.17.1 | MIT, Copyright (c) 2019 Andrew Dillon | the classic PDF writer (encryption, `prepare`, `save`) |
|
|
11
11
|
| [@pdf-lib/fontkit](https://github.com/Hopding/fontkit) | 1.1.1 | MIT | reading font files |
|
|
12
|
-
| [@pdf-lib/standard-fonts](https://github.com/Hopding/standard-fonts) | 1.0.0 | MIT; the metrics are Adobe's AFM files for the 14 standard PDF fonts | Helvetica, Times and Courier widths |
|
|
12
|
+
| [@pdf-lib/standard-fonts](https://github.com/Hopding/standard-fonts) | 1.0.0 | MIT; the metrics are Adobe's AFM files for the 14 standard PDF fonts | Helvetica, Times and Courier widths: generated from its AFM data into src/engine/text/standard-metrics.js (scripts/gen-standard-metrics.mjs); the package itself is not a runtime dependency |
|
|
13
13
|
| [bwip-js](https://github.com/metafloor/bwip-js) | 4.11.4 | MIT | barcodes |
|
|
14
14
|
| [fflate](https://github.com/101arrowz/fflate) | 0.8.3 | MIT | zip and deflate (Excel, Word, PowerPoint, PDF streams) |
|
|
15
15
|
| [bidi-js](https://github.com/lojjic/bidi-js) | 1.0.3 | MIT | right-to-left text |
|