@reportwright/viewer 0.13.1 → 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.
Files changed (54) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +146 -5
  3. package/dist/{chunk-B5ZCT3UK.js → chunk-2KNQVFKW.js} +72 -45
  4. package/dist/{chunk-B5ZCT3UK.js.map → chunk-2KNQVFKW.js.map} +2 -2
  5. package/dist/{chunk-XXTAPZO4.js → chunk-D7S5DL46.js} +2 -2
  6. package/dist/{chunk-ES2LYZ6S.js → chunk-DVJYE7HZ.js} +3 -3
  7. package/dist/chunk-GOCWG6FG.js +12 -12
  8. package/dist/chunk-GRYITZPG.js +23 -23
  9. package/dist/chunk-H422SRD3.js +21 -21
  10. package/dist/{chunk-PF4RFKX2.js → chunk-NARXO3DB.js} +3 -3
  11. package/dist/{chunk-PKXTMC4J.js → chunk-OED3YZYP.js} +5 -5
  12. package/dist/{chunk-ZGRJJ6OW.js → chunk-OMCWZYRI.js} +32 -17
  13. package/dist/chunk-OMCWZYRI.js.map +6 -0
  14. package/dist/chunk-U2ZY2NPQ.js +2 -2
  15. package/dist/designer.js +327 -132
  16. package/dist/designer.js.map +3 -3
  17. package/dist/engine.worker.bwip.js +4780 -51421
  18. package/dist/engine.worker.bwip.js.map +3 -3
  19. package/dist/engine.worker.js +5675 -59626
  20. package/dist/engine.worker.js.map +3 -3
  21. package/dist/peer/{chunk-7IP67PA6.js → chunk-6KUUNDNN.js} +47 -20
  22. package/dist/peer/{chunk-7IP67PA6.js.map → chunk-6KUUNDNN.js.map} +1 -1
  23. package/dist/peer/chunk-A6UXBSTP.js +21 -21
  24. package/dist/peer/{chunk-3EYYRJR4.js → chunk-FN3FXACD.js} +3 -3
  25. package/dist/peer/{chunk-WVQQCD4M.js → chunk-ILBTPBOA.js} +32 -17
  26. package/dist/peer/chunk-ILBTPBOA.js.map +6 -0
  27. package/dist/peer/{chunk-3XZY54LM.js → chunk-JQDW5OR3.js} +5 -5
  28. package/dist/peer/chunk-MXR6JBMP.js +2 -2
  29. package/dist/peer/chunk-N42DCZZA.js +12 -12
  30. package/dist/peer/{chunk-RKFP7SDY.js → chunk-OUTKMWFM.js} +3 -3
  31. package/dist/peer/{chunk-5RUNOIS7.js → chunk-VJLMUGUI.js} +2 -2
  32. package/dist/peer/chunk-ZS3J4WBH.js +23 -23
  33. package/dist/peer/designer.js +313 -119
  34. package/dist/peer/designer.js.map +3 -3
  35. package/dist/peer/engine.worker.bwip.js +4780 -51421
  36. package/dist/peer/engine.worker.bwip.js.map +3 -3
  37. package/dist/peer/engine.worker.js +5675 -59626
  38. package/dist/peer/engine.worker.js.map +3 -3
  39. package/dist/peer/viewer.js +40 -9
  40. package/dist/peer/viewer.js.map +1 -1
  41. package/dist/viewer.d.ts +2 -0
  42. package/dist/viewer.js +40 -9
  43. package/dist/viewer.js.map +1 -1
  44. package/package.json +1 -1
  45. package/dist/chunk-ZGRJJ6OW.js.map +0 -6
  46. package/dist/peer/chunk-WVQQCD4M.js.map +0 -6
  47. /package/dist/{chunk-XXTAPZO4.js.map → chunk-D7S5DL46.js.map} +0 -0
  48. /package/dist/{chunk-ES2LYZ6S.js.map → chunk-DVJYE7HZ.js.map} +0 -0
  49. /package/dist/{chunk-PF4RFKX2.js.map → chunk-NARXO3DB.js.map} +0 -0
  50. /package/dist/{chunk-PKXTMC4J.js.map → chunk-OED3YZYP.js.map} +0 -0
  51. /package/dist/peer/{chunk-3EYYRJR4.js.map → chunk-FN3FXACD.js.map} +0 -0
  52. /package/dist/peer/{chunk-3XZY54LM.js.map → chunk-JQDW5OR3.js.map} +0 -0
  53. /package/dist/peer/{chunk-RKFP7SDY.js.map → chunk-OUTKMWFM.js.map} +0 -0
  54. /package/dist/peer/{chunk-5RUNOIS7.js.map → chunk-VJLMUGUI.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,44 @@
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
+
5
43
  ## 0.13.1 — 2026-10-09
6
44
 
7
45
  ### Fixed
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
  [![npm](https://img.shields.io/npm/v/%40reportwright%2Fviewer)](https://www.npmjs.com/package/@reportwright/viewer) [![license](https://img.shields.io/badge/license-MIT-blue)](https://github.com/MrArun005/reportwright/blob/main/LICENSE) [![Socket](https://socket.dev/api/badge/npm/package/@reportwright/viewer)](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
@@ -138,11 +265,11 @@ Types are included (`ViewerOptions`, `DesignerOptions`, …). Framework wrappers
138
265
 
139
266
  ### Viewer toolbar: `toolbar.hide`
140
267
 
141
- `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 gear.
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.
142
269
 
143
270
  | Key | Hides |
144
271
  |---|---|
145
- | `export` | the Export menu: every format and the options gear (Print stays) |
272
+ | `export` | the Export menu: every format and the Export options button (Print stays) |
146
273
  | `pdf`, `excel`, `word`, `powerpoint`, `html`, `csv`, `json` | that one export format |
147
274
  | `print` | the Print button |
148
275
  | `search` | the search box and its match controls |
@@ -151,10 +278,18 @@ Types are included (`ViewerOptions`, `DesignerOptions`, …). Framework wrappers
151
278
  | `sidebar` | the page thumbnails and the document map buttons |
152
279
  | `parameters` | the Parameters button |
153
280
  | `run`, `viewMode`, `fullScreen`, `stats` | those single items (use their id) |
154
- | `exportOptions` | the options gear (the formats stay) |
281
+ | `exportOptions` | the Export options button (the formats stay) |
155
282
 
156
283
  Any other key is taken as an item id. Unknown keys hide nothing.
157
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
+
158
293
  ### Controlling a mounted viewer: `ViewerHandle`
159
294
 
160
295
  `mountViewer` returns a handle (the React, Vue, Svelte and Angular wrappers give you the same one through their ready callback or event):
@@ -167,15 +302,21 @@ Any other key is taken as an item id. Unknown keys hide nothing.
167
302
  | `getPageCount()` | the page count of the last run (0 before the first) |
168
303
  | `print()` | opens the print dialog for the PDF |
169
304
  | `export(format)` | `Promise<Blob>`: `format` is `pdf`, `xlsx`, `docx`, `pptx`, `html`, `csv` or `json` (or the item ids `excel`, `word`, `powerpoint`) |
170
- | `on(event, fn)` | listens for `ready` (a run finished, detail: page count), `error` (detail: message), `page` (detail: current page), `parameters` (detail: the parameters); returns an unsubscribe function |
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 |
171
306
  | `unmount()` | removes the viewer |
172
307
 
173
308
  ```js
174
309
  const viewer = mountViewer('#report', { server, report: 'loan-statement' });
175
310
  viewer.setParameters({ accountId: 'LN-2' }); // re-runs; 'ready' fires when it is done
176
- const pdf = await viewer.export('pdf'); // a Blob
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
+ };
177
315
  ```
178
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
+
179
320
  ## Size
180
321
 
181
322
  What a page downloads when the viewer mounts: **847 KB gzipped** (0.7.3: 877 KB), readable unminified code with
@@ -22,7 +22,7 @@ import {
22
22
  serverPdfUrl,
23
23
  subsetter,
24
24
  usingWorker
25
- } from "./chunk-ES2LYZ6S.js";
25
+ } from "./chunk-DVJYE7HZ.js";
26
26
  import {
27
27
  NO_CJK_FONTS
28
28
  } from "./chunk-BR5K6SBL.js";
@@ -45,9 +45,9 @@ import {
45
45
  __toESM
46
46
  } from "./chunk-OLLMACWA.js";
47
47
 
48
- // node_modules/react/cjs/react.production.js
48
+ // ../reportwright/node_modules/react/cjs/react.production.js
49
49
  var require_react_production = __commonJS({
50
- "node_modules/react/cjs/react.production.js"(exports) {
50
+ "../reportwright/node_modules/react/cjs/react.production.js"(exports) {
51
51
  "use strict";
52
52
  /**
53
53
  * @license React
@@ -506,9 +506,9 @@ var require_react_production = __commonJS({
506
506
  }
507
507
  });
508
508
 
509
- // node_modules/react/index.js
509
+ // ../reportwright/node_modules/react/index.js
510
510
  var require_react = __commonJS({
511
- "node_modules/react/index.js"(exports, module) {
511
+ "../reportwright/node_modules/react/index.js"(exports, module) {
512
512
  "use strict";
513
513
  if (true) {
514
514
  module.exports = require_react_production();
@@ -518,9 +518,9 @@ var require_react = __commonJS({
518
518
  }
519
519
  });
520
520
 
521
- // node_modules/scheduler/cjs/scheduler.production.js
521
+ // ../reportwright/node_modules/scheduler/cjs/scheduler.production.js
522
522
  var require_scheduler_production = __commonJS({
523
- "node_modules/scheduler/cjs/scheduler.production.js"(exports) {
523
+ "../reportwright/node_modules/scheduler/cjs/scheduler.production.js"(exports) {
524
524
  "use strict";
525
525
  /**
526
526
  * @license React
@@ -801,9 +801,9 @@ var require_scheduler_production = __commonJS({
801
801
  }
802
802
  });
803
803
 
804
- // node_modules/scheduler/index.js
804
+ // ../reportwright/node_modules/scheduler/index.js
805
805
  var require_scheduler = __commonJS({
806
- "node_modules/scheduler/index.js"(exports, module) {
806
+ "../reportwright/node_modules/scheduler/index.js"(exports, module) {
807
807
  "use strict";
808
808
  if (true) {
809
809
  module.exports = require_scheduler_production();
@@ -813,9 +813,9 @@ var require_scheduler = __commonJS({
813
813
  }
814
814
  });
815
815
 
816
- // node_modules/react-dom/cjs/react-dom.production.js
816
+ // ../reportwright/node_modules/react-dom/cjs/react-dom.production.js
817
817
  var require_react_dom_production = __commonJS({
818
- "node_modules/react-dom/cjs/react-dom.production.js"(exports) {
818
+ "../reportwright/node_modules/react-dom/cjs/react-dom.production.js"(exports) {
819
819
  "use strict";
820
820
  /**
821
821
  * @license React
@@ -979,9 +979,9 @@ var require_react_dom_production = __commonJS({
979
979
  }
980
980
  });
981
981
 
982
- // node_modules/react-dom/index.js
982
+ // ../reportwright/node_modules/react-dom/index.js
983
983
  var require_react_dom = __commonJS({
984
- "node_modules/react-dom/index.js"(exports, module) {
984
+ "../reportwright/node_modules/react-dom/index.js"(exports, module) {
985
985
  "use strict";
986
986
  function checkDCE() {
987
987
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined" || typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== "function") {
@@ -1005,9 +1005,9 @@ var require_react_dom = __commonJS({
1005
1005
  }
1006
1006
  });
1007
1007
 
1008
- // node_modules/react-dom/cjs/react-dom-client.production.js
1008
+ // ../reportwright/node_modules/react-dom/cjs/react-dom-client.production.js
1009
1009
  var require_react_dom_client_production = __commonJS({
1010
- "node_modules/react-dom/cjs/react-dom-client.production.js"(exports) {
1010
+ "../reportwright/node_modules/react-dom/cjs/react-dom-client.production.js"(exports) {
1011
1011
  "use strict";
1012
1012
  /**
1013
1013
  * @license React
@@ -2122,9 +2122,9 @@ var require_react_dom_client_production = __commonJS({
2122
2122
  node.textContent = text;
2123
2123
  }
2124
2124
  var unitlessNumbers = new Set(
2125
- "animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIn\
2126
- dex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitB\
2127
- oxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp".split(
2125
+ ("animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIn"+
2126
+ "dex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitB"+
2127
+ "oxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp").split(
2128
2128
  " "
2129
2129
  )
2130
2130
  );
@@ -2906,8 +2906,8 @@ oxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex Web
2906
2906
  var TRANSITION_CANCEL = getVendorPrefixedEventName("transitioncancel");
2907
2907
  var TRANSITION_END = getVendorPrefixedEventName("transitionend");
2908
2908
  var topLevelEventsToReactNames = /* @__PURE__ */ new Map();
2909
- var simpleEventPluginEvents = "abort auxClick beforeToggle cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error fullscreenChange fullscreenError gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouse\
2910
- Move mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(
2909
+ var simpleEventPluginEvents = ("abort auxClick beforeToggle cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error fullscreenChange fullscreenError gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouse"+
2910
+ "Move mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel").split(
2911
2911
  " "
2912
2912
  );
2913
2913
  simpleEventPluginEvents.push("scrollEnd");
@@ -14600,9 +14600,9 @@ Move mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDo
14600
14600
  }
14601
14601
  });
14602
14602
 
14603
- // node_modules/react-dom/client.js
14603
+ // ../reportwright/node_modules/react-dom/client.js
14604
14604
  var require_client = __commonJS({
14605
- "node_modules/react-dom/client.js"(exports, module) {
14605
+ "../reportwright/node_modules/react-dom/client.js"(exports, module) {
14606
14606
  "use strict";
14607
14607
  function checkDCE() {
14608
14608
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined" || typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== "function") {
@@ -14626,9 +14626,9 @@ var require_client = __commonJS({
14626
14626
  }
14627
14627
  });
14628
14628
 
14629
- // node_modules/react/cjs/react-jsx-runtime.production.js
14629
+ // ../reportwright/node_modules/react/cjs/react-jsx-runtime.production.js
14630
14630
  var require_react_jsx_runtime_production = __commonJS({
14631
- "node_modules/react/cjs/react-jsx-runtime.production.js"(exports) {
14631
+ "../reportwright/node_modules/react/cjs/react-jsx-runtime.production.js"(exports) {
14632
14632
  "use strict";
14633
14633
  /**
14634
14634
  * @license React
@@ -14665,9 +14665,9 @@ var require_react_jsx_runtime_production = __commonJS({
14665
14665
  }
14666
14666
  });
14667
14667
 
14668
- // node_modules/react/jsx-runtime.js
14668
+ // ../reportwright/node_modules/react/jsx-runtime.js
14669
14669
  var require_jsx_runtime = __commonJS({
14670
- "node_modules/react/jsx-runtime.js"(exports, module) {
14670
+ "../reportwright/node_modules/react/jsx-runtime.js"(exports, module) {
14671
14671
  "use strict";
14672
14672
  if (true) {
14673
14673
  module.exports = require_react_jsx_runtime_production();
@@ -19363,8 +19363,8 @@ var r4_default = {
19363
19363
  // src/i18n/b2.js
19364
19364
  var LANGS = ["en", "hi", "es", "fr", "de", "ja", "zh", "pt-BR", "ar"];
19365
19365
  var ROWS = {
19366
- b2_skipBlank: ["Skip when the parameter is blank", "पैरामीटर खाली हो तो छोड़ें", "Omitir si el parámetro está vacío", "Ignorer si le paramètre est vide", "Überspringen, wenn der Parameter leer ist", "パラメーターが空のときはスキップ", "参数为空时跳过", "Ignorar quando o parâmetro estiver vazio", "تخطَّ عندما تكون المعلمة فا\
19367
- رغة"],
19366
+ b2_skipBlank: ["Skip when the parameter is blank", "पैरामीटर खाली हो तो छोड़ें", "Omitir si el parámetro está vacío", "Ignorer si le paramètre est vide", "Überspringen, wenn der Parameter leer ist", "パラメーターが空のときはスキップ", "参数为空时跳过", "Ignorar quando o parâmetro estiver vazio", ("تخطَّ عندما تكون المعلمة فا"+
19367
+ "رغة")],
19368
19368
  // viewer
19369
19369
  b2_pageOf: ["Page {n} of {total}", "पृष्ठ {n} / {total}", "Página {n} de {total}", "Page {n} sur {total}", "Seite {n} von {total}", "{total} ページ中 {n} ページ", "第 {n} 页,共 {total} 页", "Página {n} de {total}", "الصفحة {n} من {total}"],
19370
19370
  b2_pageN: ["Page {n}", "पृष्ठ {n}", "Página {n}", "Page {n}", "Seite {n}", "{n} ページ", "第 {n} 页", "Página {n}", "الصفحة {n}"],
@@ -19386,8 +19386,8 @@ var ROWS = {
19386
19386
  b2_view: ["View", "दृश्य", "Vista", "Affichage", "Ansicht", "表示", "视图", "Exibir", "عرض"],
19387
19387
  b2_previewGroup: ["Preview", "पूर्वावलोकन", "Vista previa", "Aperçu", "Vorschau", "プレビュー", "预览", "Visualização", "معاينة"],
19388
19388
  b2_insertItem: ["Insert: {item}", "डालें: {item}", "Insertar: {item}", "Insérer : {item}", "Einfügen: {item}", "挿入: {item}", "插入:{item}", "Inserir: {item}", "إدراج: {item}"],
19389
- b2_insertHint: ["Goes inside the selected list or container, else below the body", "चुनी गई सूची या कंटेनर के अंदर, वरना बॉडी के नीचे जाता है", "Va dentro de la lista o el contenedor seleccionado; si no, debajo del cuerpo", "Va dans la liste ou le conteneur sélectionné, sinon sous le corps", "Kommt in die a\
19390
- usgewählte Liste oder den Container, sonst unter den Hauptteil", "選択したリストやコンテナーの中に、なければ本文の下に入ります", "放入所选列表或容器中,否则放在正文下方", "Vai dentro da lista ou do contêiner selecionado; senão, abaixo do corpo", "يُدرج داخل القائمة أو الحاوية المحددة، وإلا أسفل المتن"],
19389
+ b2_insertHint: ["Goes inside the selected list or container, else below the body", "चुनी गई सूची या कंटेनर के अंदर, वरना बॉडी के नीचे जाता है", "Va dentro de la lista o el contenedor seleccionado; si no, debajo del cuerpo", "Va dans la liste ou le conteneur sélectionné, sinon sous le corps", ("Kommt in die a"+
19390
+ "usgewählte Liste oder den Container, sonst unter den Hauptteil"), "選択したリストやコンテナーの中に、なければ本文の下に入ります", "放入所选列表或容器中,否则放在正文下方", "Vai dentro da lista ou do contêiner selecionado; senão, abaixo do corpo", "يُدرج داخل القائمة أو الحاوية المحددة، وإلا أسفل المتن"],
19391
19391
  b2_toolbox: ["Toolbox", "टूलबॉक्स", "Herramientas", "Boîte à outils", "Werkzeuge", "ツールボックス", "工具箱", "Ferramentas", "الأدوات"],
19392
19392
  b2_data: ["Data", "डेटा", "Datos", "Données", "Daten", "データ", "数据", "Dados", "البيانات"],
19393
19393
  b2_outline: ["Outline", "रूपरेखा", "Esquema", "Structure", "Gliederung", "アウトライン", "大纲", "Estrutura", "المخطط"],
@@ -19402,15 +19402,34 @@ usgewählte Liste oder den Container, sonst unter den Hauptteil", "選択した
19402
19402
  b2_selCell: ["Cell in {name}", "{name} में सेल", "Celda de {name}", "Cellule de {name}", "Zelle in {name}", "{name} のセル", "{name} 中的单元格", "Célula em {name}", "خلية في {name}"],
19403
19403
  b2_pageInfo: ["Page {size} · {w} × {h} {unit}", "पृष्ठ {size} · {w} × {h} {unit}", "Página {size} · {w} × {h} {unit}", "Page {size} · {w} × {h} {unit}", "Seite {size} · {w} × {h} {unit}", "ページ {size} · {w} × {h} {unit}", "页面 {size} · {w} × {h} {unit}", "Página {size} · {w} × {h} {unit}", "الصفحة {size} · {w} × {h} {unit}"],
19404
19404
  // batch 9 (designer bugs)
19405
- b9_nothingToPaste: ["Nothing to paste: copy items in a designer first (Ctrl+C)", "चिपकाने को कुछ नहीं: पहले डिज़ाइनर में आइटम कॉपी करें (Ctrl+C)", "Nada que pegar: copie primero elementos en un diseñador (Ctrl+C)", "Rien à coller : copiez d’abord des éléments dans un concepteur (Ctrl+C)", "Nichts zum Einf\
19406
- ügen: zuerst Elemente in einem Designer kopieren (Strg+C)", "貼り付けるものがありません。先にデザイナーで項目をコピーしてください (Ctrl+C)", "没有可粘贴的内容:请先在设计器中复制项目 (Ctrl+C)", "Nada para colar: copie primeiro itens em um designer (Ctrl+C)", "لا شيء للصق: انسخ عناصر في مصمم أولاً (Ctrl+C)"],
19405
+ b9_nothingToPaste: ["Nothing to paste: copy items in a designer first (Ctrl+C)", "चिपकाने को कुछ नहीं: पहले डिज़ाइनर में आइटम कॉपी करें (Ctrl+C)", "Nada que pegar: copie primero elementos en un diseñador (Ctrl+C)", "Rien à coller : copiez d’abord des éléments dans un concepteur (Ctrl+C)", ("Nichts zum Einf"+
19406
+ "ügen: zuerst Elemente in einem Designer kopieren (Strg+C)"), "貼り付けるものがありません。先にデザイナーで項目をコピーしてください (Ctrl+C)", "没有可粘贴的内容:请先在设计器中复制项目 (Ctrl+C)", "Nada para colar: copie primeiro itens em um designer (Ctrl+C)", "لا شيء للصق: انسخ عناصر في مصمم أولاً (Ctrl+C)"],
19407
19407
  b9_itemLabel: ["{type} {name}, x {x}, y {y}", "{type} {name}, x {x}, y {y}", "{type} {name}, x {x}, y {y}", "{type} {name}, x {x}, y {y}", "{type} {name}, x {x}, y {y}", "{type} {name}、x {x}、y {y}", "{type} {name},x {x},y {y}", "{type} {name}, x {x}, y {y}", "{type} {name}، x {x}، y {y}"],
19408
19408
  b9_outlineKeys: ["Up and Down move between rows; Enter or Space selects (Shift adds); then Delete removes and the arrows move the selection on the page", "ऊपर और नीचे पंक्तियों के बीच जाते हैं; Enter या Space चुनता है (Shift जोड़ता है); फिर Delete हटाता है और तीर पेज पर चयन को खिसकाते हैं",
19409
- "Arriba y Abajo cambian de fila; Intro o Espacio selecciona (Mayús añade); luego Supr elimina y las flechas mueven la selección en la página", "Haut et Bas passent d’une ligne à l’autre ; Entrée ou Espace sélectionne (Maj ajoute) ; ensuite Suppr supprime et les flèches déplacent la sélection sur la page", "Auf und Ab wechseln die Zeile; Eingabe oder Leertaste wählt aus (Umschalt fü\
19410
- gt hinzu); dann löscht Entf und die Pfeile verschieben die Auswahl auf der Seite", "上下で行を移動、Enter または Space で選択 (Shift で追加)。その後 Delete で削除、矢印でページ上の選択を移動", "上下键在行间移动;Enter 或空格选择(Shift 添加);然后 Delete 删除,方向键在页面上移动所选项", "Cima e Baixo mudam de linha; Enter \
19411
- ou Espaço seleciona (Shift adiciona); depois Delete remove e as setas movem a seleção na página", "السهمان لأعلى ولأسفل للتنقل بين الصفوف؛ Enter أو المسافة للتحديد (Shift للإضافة)؛ ثم Delete للحذف والأسهم لتحريك التحديد في الصفحة"],
19409
+ "Arriba y Abajo cambian de fila; Intro o Espacio selecciona (Mayús añade); luego Supr elimina y las flechas mueven la selección en la página", "Haut et Bas passent d’une ligne à l’autre ; Entrée ou Espace sélectionne (Maj ajoute) ; ensuite Suppr supprime et les flèches déplacent la sélection sur la page", ("Auf und Ab wechseln die Zeile; Eingabe oder Leertaste wählt aus (Umschalt fü"+
19410
+ "gt hinzu); dann löscht Entf und die Pfeile verschieben die Auswahl auf der Seite"), "上下で行を移動、Enter または Space で選択 (Shift で追加)。その後 Delete で削除、矢印でページ上の選択を移動", "上下键在行间移动;Enter 或空格选择(Shift 添加);然后 Delete 删除,方向键在页面上移动所选项", ("Cima e Baixo mudam de linha; Enter "+
19411
+ "ou Espaço seleciona (Shift adiciona); depois Delete remove e as setas movem a seleção na página"), "السهمان لأعلى ولأسفل للتنقل بين الصفوف؛ Enter أو المسافة للتحديد (Shift للإضافة)؛ ثم Delete للحذف والأسهم لتحريك التحديد في الصفحة"],
19412
19412
  p_field_label: ["Label (the name a screen reader says)", "लेबल (स्क्रीन रीडर जो नाम बोलता है)", "Etiqueta (el nombre que dice un lector de pantalla)", "Libellé (le nom que lit un lecteur d’écran)", "Beschriftung (der Name, den ein Screenreader vorliest)", "ラベル (スクリーンリーダーが読み上げる名前)", "标签(屏幕阅读器读出的名称)",
19413
- "Rótulo (o nome que um leitor de tela diz)", "التسمية (الاسم الذي يقرؤه قارئ الشاشة)"]
19413
+ "Rótulo (o nome que um leitor de tela diz)", "التسمية (الاسم الذي يقرؤه قارئ الشاشة)"],
19414
+ // 0.13.2 (designer and viewer UI review)
19415
+ c132_nudge1: ["Nudge 1 pt (1 grid step with Snap to grid)", "1 pt खिसकाएँ (स्नैप टू ग्रिड के साथ 1 ग्रिड कदम)", "Desplazar 1 pt (1 paso de cuadrícula con Ajustar a la cuadrícula)", "Déplacer de 1 pt (1 pas de grille avec Aligner sur la grille)", "Um 1 pt verschieben (1 Rasterschritt mit „Am Raster ausrichten“)", ("1 pt 移動 (グリッ"+
19416
+ "ドにスナップ時は 1 目盛り)"), "微移 1 pt(启用对齐网格时为 1 个网格单位)", "Mover 1 pt (1 passo da grade com Ajustar à grade)", "تحريك 1 نقطة (خطوة شبكة واحدة مع المحاذاة إلى الشبكة)"],
19417
+ c132_nudge10: ["Nudge 10 pt (10 grid steps with Snap to grid)", "10 pt खिसकाएँ (स्नैप टू ग्रिड के साथ 10 ग्रिड कदम)", "Desplazar 10 pt (10 pasos de cuadrícula con Ajustar a la cuadrícula)", "Déplacer de 10 pt (10 pas de grille avec Aligner sur la grille)", "Um 10 pt verschieben (10 Rasterschritte mit „Am Raster ausrichten“)",
19418
+ "10 pt 移動 (グリッドにスナップ時は 10 目盛り)", "微移 10 pt(启用对齐网格时为 10 个网格单位)", "Mover 10 pt (10 passos da grade com Ajustar à grade)", "تحريك 10 نقاط (10 خطوات شبكة مع المحاذاة إلى الشبكة)"],
19419
+ c132_warnings: ["{n} warnings", "{n} चेतावनियाँ", "{n} advertencias", "{n} avertissements", "{n} Warnungen", "警告 {n} 件", "{n} 条警告", "{n} avisos", "{n} تحذيرات"],
19420
+ c132_warning1: ["1 warning", "1 चेतावनी", "1 advertencia", "1 avertissement", "1 Warnung", "警告 1 件", "1 条警告", "1 aviso", "تحذير واحد"],
19421
+ c132_detected: ["detected", "पहचाना गया", "detectado", "détecté", "erkannt", "検出", "已检测", "detectado", "مكتشف"],
19422
+ c132_detectedHint: ["Fields detected from the data, not declared in the data set (Edit declares them)", "डेटा से पहचाने गए फ़ील्ड, डेटा सेट में घोषित नहीं (संपादित करें उन्हें घोषित करता है)", ("Campos detectados en los datos, no declarados en el conjunto de datos "+
19423
+ "(Editar los declara)"), "Champs détectés dans les données, non déclarés dans le jeu de données (Modifier les déclare)", "Aus den Daten erkannte Felder, im Dataset nicht deklariert (Bearbeiten deklariert sie)", "データから検出したフィールド (データセットでは未宣言。編集で宣言できます)", "从数据中检测到的字段,未在数据集中声明(编辑可声明它们)",
19424
+ "Campos detectados nos dados, não declarados no conjunto de dados (Editar os declara)", "حقول مكتشفة من البيانات، غير معرّفة في مجموعة البيانات (التحرير يعرّفها)"],
19425
+ c132_moreInfo: ["More information", "अधिक जानकारी", "Más información", "Plus d’informations", "Weitere Informationen", "詳細情報", "更多信息", "Mais informações", "مزيد من المعلومات"],
19426
+ c132_liveParams: ["Apply parameters as the reader changes them (off: only when the reader clicks View report)", "पाठक के बदलते ही पैरामीटर लागू करें (बंद: केवल जब पाठक रिपोर्ट देखें पर क्लिक करे)", ("Aplicar los parámetros a medida que el lector los cambia (desactivado: "+
19427
+ "solo al hacer clic en Ver informe)"), "Appliquer les paramètres dès que le lecteur les change (désactivé : seulement quand il clique sur Afficher le rapport)", "Parameter anwenden, sobald der Leser sie ändert (aus: erst wenn er auf „Bericht anzeigen“ klickt)", "閲覧者が変更したらすぐにパラメーターを適用 (オフ: 「レポートを表示」をクリックしたときのみ)",
19428
+ "读者更改参数时立即应用(关闭:仅在读者点击“查看报表”时应用)", "Aplicar os parâmetros conforme o leitor os altera (desligado: só quando o leitor clica em Ver relatório)", "تطبيق المعلمات عند تغيير القارئ لها (عند الإيقاف: فقط عند النقر على عرض التقرير)"],
19429
+ c132_panelColumnsHint: ["For the whole report. On a wide screen, more than one column puts the panel above the pages, with the parameters in a grid; on a phone it stays one column.", "पूरी रिपोर्ट के लिए। चौड़ी स्क्रीन पर एक से अधिक कॉलम पैनल को पृष्ठों के ऊपर रखते हैं, पैरामीटर ग्रिड में; फ़ोन पर यह एक कॉलम रहता है।",
19430
+ "Para todo el informe. En una pantalla ancha, más de una columna pone el panel encima de las páginas, con los parámetros en cuadrícula; en un teléfono queda en una columna.", "Pour tout le rapport. Sur un écran large, plus d’une colonne place le panneau au-dessus des pages, avec les paramètres en grille ; sur un téléphone il reste sur une colonne.", ("Für den ganzen Bericht. Auf einem "+
19431
+ "breiten Bildschirm setzt mehr als eine Spalte das Feld über die Seiten, mit den Parametern im Raster; auf dem Telefon bleibt es einspaltig."), "レポート全体の設定です。広い画面では 2 列以上にするとパネルがページの上に表示され、パラメーターがグリッドに並びます。スマートフォンでは 1 列のままです。", ("适用于整个报表。在宽屏上,多于一列会把面板放在页面上方"+
19432
+ ",参数排成网格;在手机上仍为一列。"), "Para todo o relatório. Em uma tela larga, mais de uma coluna coloca o painel acima das páginas, com os parâmetros em grade; no celular ele fica em uma coluna.", "للتقرير كله. على شاشة عريضة، أكثر من عمود يضع اللوحة فوق الصفحات والمعلمات في شبكة؛ على الهاتف تبقى عمودًا واحدًا."]
19414
19433
  };
19415
19434
  var b2_default = Object.fromEntries(LANGS.map((l, i) => [l, Object.fromEntries(Object.entries(ROWS).map(([k, v]) => [k, v[i]]))]));
19416
19435
 
@@ -19478,7 +19497,7 @@ async function exportBlob(fmt, model, def, opt = {}) {
19478
19497
  if (fmt === "csv") return new Blob([(await import("./chunk-47ZAKRVN.js")).exportCsv(model, { locale: def.locale, currency: def.currency })], { type: "text/csv;charset=utf-8" });
19479
19498
  if (fmt === "html" && opt.interactive !== false && o.html === "interactive") {
19480
19499
  try {
19481
- const { exportInteractiveHtml } = await import("./chunk-PF4RFKX2.js");
19500
+ const { exportInteractiveHtml } = await import("./chunk-NARXO3DB.js");
19482
19501
  const { html } = await exportInteractiveHtml(def, { params: opt.params, reportId: opt.reportId, lang: opt.lang, model });
19483
19502
  return new Blob([html], { type: "text/html;charset=utf-8" });
19484
19503
  } catch (e) {
@@ -19641,7 +19660,8 @@ var P = {
19641
19660
  search: "M7 12a5 5 0 1 0 0-10 5 5 0 0 0 0 10zM14 14l-3.5-3.5",
19642
19661
  print: "M4.5 6V1.5h7V6M4.5 11.5h-2.5v-5.5h12v5.5h-2.5M4.5 9.5h7v5h-7z",
19643
19662
  download: "M8 2v8.5M4.5 7L8 10.5 11.5 7M2.5 13.5h11",
19644
- gear: "M8 10.2a2.2 2.2 0 1 0 0-4.4 2.2 2.2 0 0 0 0 4.4zM8 1.5v2M8 12.5v2M1.5 8h2M12.5 8h2M3.4 3.4l1.4 1.4M11.2 11.2l1.4 1.4M3.4 12.6l1.4-1.4M11.2 4.8l1.4-1.4",
19663
+ sliders: "M2 4h6M11 4h3M9.5 2.5v3M2 8h1.5M6.5 8h7.5M5 6.5v3M2 12h7.5M12.5 12h1.5M11 10.5v3",
19664
+ // Export options (a sun-like gear read as brightness)
19645
19665
  sidebar: "M2 2.5h12v11H2zM6 2.5v11",
19646
19666
  pages: "M3 1.5h7l3 3v10H3zM10 1.5v3h3M5.5 8h5M5.5 10.5h5",
19647
19667
  toc: "M2.5 4h1M6 4h7.5M2.5 8h1M6 8h7.5M2.5 12h1M6 12h7.5",
@@ -19784,7 +19804,7 @@ var urlWithDrill = (list) => {
19784
19804
  else u.searchParams.delete(DRILL_KEY);
19785
19805
  return u.toString();
19786
19806
  };
19787
- function ReportViewer({ definition: rootDef, reportId: rootReportId, params: rootParams, title, compact = false, autoRun = true, lang: langIn = "en", onDrill, exportHtmlOptions, toolbar, viewMode = "continuous", onExported, urlState = false, onReady, control, onEvent }) {
19807
+ function ReportViewer({ definition: rootDef, reportId: rootReportId, params: rootParams, title, compact = false, autoRun = true, lang: langIn = "en", onDrill, exportHtmlOptions, toolbar, viewMode = "continuous", onExported, urlState = false, onReady, control, onEvent, showWarnings = false }) {
19788
19808
  const lang = pickLang(langIn);
19789
19809
  const dir = dirOf(lang);
19790
19810
  const T = (k, v) => t(lang, k, v);
@@ -19808,6 +19828,7 @@ function ReportViewer({ definition: rootDef, reportId: rootReportId, params: roo
19808
19828
  onReady?.(error);
19809
19829
  }
19810
19830
  };
19831
+ const announce = (0, import_react.useRef)(null);
19811
19832
  const [note, setNote] = (0, import_react.useState)(null);
19812
19833
  const [zoom, setZoom] = (0, import_react.useState)(() => rootDef?.page?.size === "Pageless" ? "fit" : "page");
19813
19834
  const [current, setCurrent] = (0, import_react.useState)(1);
@@ -19879,8 +19900,7 @@ function ReportViewer({ definition: rootDef, reportId: rootReportId, params: roo
19879
19900
  setModel(m);
19880
19901
  const fonts = failed.length ? T("fontsDidNotLoad", { fonts: [...new Set(failed.map((f) => f.key))].join(", ") }) : null;
19881
19902
  setStatus({ state: "done", fonts });
19882
- ready(failed[0]?.error || null);
19883
- onEvent?.("ready", { pages: m.pages.length });
19903
+ announce.current = { error: failed[0]?.error || null, pages: m.pages.length };
19884
19904
  if (keepScroll) requestAnimationFrame(() => scroller.current?.scrollTo({ top }));
19885
19905
  else {
19886
19906
  setCurrent(1);
@@ -20271,6 +20291,13 @@ function ReportViewer({ definition: rootDef, reportId: rootReportId, params: roo
20271
20291
  (0, import_react.useEffect)(() => () => {
20272
20292
  if (control) control.current = null;
20273
20293
  }, [control]);
20294
+ (0, import_react.useEffect)(() => {
20295
+ const a = announce.current;
20296
+ if (!a) return;
20297
+ announce.current = null;
20298
+ ready(a.error);
20299
+ onEvent?.("ready", { pages: a.pages });
20300
+ });
20274
20301
  const lastEvent = (0, import_react.useRef)({ page: current, params: JSON.stringify(params) });
20275
20302
  (0, import_react.useEffect)(() => {
20276
20303
  if (lastEvent.current.page !== current) {
@@ -20409,7 +20436,7 @@ function ReportViewer({ definition: rootDef, reportId: rootReportId, params: roo
20409
20436
  id: "exportOptions",
20410
20437
  group: "export",
20411
20438
  node: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vexp", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "btn sm icon", "aria-label": T("exportOptions"), title: T("exportOptions"), "aria-expanded": xmenu, "aria-haspopup": "true", "data-testid": "export-options", onClick: () => setXmenu((v) => !v), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
20412
- Icon, { name: "gear" }) }) })
20439
+ Icon, { name: "sliders" }) }) })
20413
20440
  }
20414
20441
  ].filter(Boolean);
20415
20442
  const items = arrangeToolbar(builtIns, toolbar || {});
@@ -20652,10 +20679,10 @@ function ReportViewer({ definition: rootDef, reportId: rootReportId, params: roo
20652
20679
  ] }),
20653
20680
  status.state === "running" && status.retry && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vmsg", role: "status", "data-testid": "viewer-busy", children: T("r4_busyRetry", { n: status.retry.attempt, max: status.retry.max }) }),
20654
20681
  !model && status.state === "running" && !status.retry && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Skeleton, { def: renderDef, scale: zoom === "fit" || narrow ? fitW / 600 : Math.min(fitW / 600, fitH / 850), T }),
20655
- model?.warnings?.length > 0 && // content cut off (past the page edge or bottom): the warnings open by themselves and the summary says so
20682
+ showWarnings && model?.warnings?.length > 0 && // content cut off (past the page edge or bottom): the warnings open by themselves and the summary says so
20656
20683
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("details", { className: "warnings", open: hasErrorCells || model.clipped?.length > 0 || void 0, "data-testid": "viewer-warnings", children: [
20657
20684
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("summary", { children: [
20658
- T("warnings", { n: model.warnings.length }),
20685
+ model.warnings.length === 1 ? T("c132_warning1") : T("c132_warnings", { n: model.warnings.length }),
20659
20686
  model.clipped?.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("b", { "data-testid": "viewer-clipped", children: [
20660
20687
  " · ",
20661
20688
  T("r4_clipped", { n: model.clipped.length })
@@ -20708,4 +20735,4 @@ export {
20708
20735
  ReportViewer,
20709
20736
  uiFontCss
20710
20737
  };
20711
- //# sourceMappingURL=chunk-B5ZCT3UK.js.map
20738
+ //# sourceMappingURL=chunk-2KNQVFKW.js.map