@shbernal/ts-pptx 0.0.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 (81) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +238 -0
  3. package/dist/autopage-tmfjRzL4.js +420 -0
  4. package/dist/autopage-tmfjRzL4.js.map +1 -0
  5. package/dist/browser.d.ts +23 -0
  6. package/dist/browser.d.ts.map +1 -0
  7. package/dist/browser.js +103 -0
  8. package/dist/browser.js.map +1 -0
  9. package/dist/diagnostics-DYQC7xLV.js +0 -0
  10. package/dist/diagnostics-DYQC7xLV.js.map +1 -0
  11. package/dist/diagnostics-DzY9Tyfm.d.ts +693 -0
  12. package/dist/diagnostics-DzY9Tyfm.d.ts.map +1 -0
  13. package/dist/embedded-fonts-MaynAHa9.js +94 -0
  14. package/dist/embedded-fonts-MaynAHa9.js.map +1 -0
  15. package/dist/enums-D3aF4QGb.d.ts +452 -0
  16. package/dist/enums-D3aF4QGb.d.ts.map +1 -0
  17. package/dist/errors-DGE9zh3U.js +93 -0
  18. package/dist/errors-DGE9zh3U.js.map +1 -0
  19. package/dist/errors-DRLpOpgQ.d.ts +160 -0
  20. package/dist/errors-DRLpOpgQ.d.ts.map +1 -0
  21. package/dist/fit-CbxyHN69.js +0 -0
  22. package/dist/fit-CbxyHN69.js.map +1 -0
  23. package/dist/html-dom-wVa3TiG7.js +666 -0
  24. package/dist/html-dom-wVa3TiG7.js.map +1 -0
  25. package/dist/html.d.ts +26 -0
  26. package/dist/html.d.ts.map +1 -0
  27. package/dist/html.js +60 -0
  28. package/dist/html.js.map +1 -0
  29. package/dist/image-size-C5Z1sKof.js +252 -0
  30. package/dist/image-size-C5Z1sKof.js.map +1 -0
  31. package/dist/index.d.ts +24 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +75 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/inspect.d.ts +173 -0
  36. package/dist/inspect.d.ts.map +1 -0
  37. package/dist/inspect.js +285 -0
  38. package/dist/inspect.js.map +1 -0
  39. package/dist/math.d.ts +37 -0
  40. package/dist/math.d.ts.map +1 -0
  41. package/dist/math.js +106 -0
  42. package/dist/math.js.map +1 -0
  43. package/dist/measure.d.ts +223 -0
  44. package/dist/measure.d.ts.map +1 -0
  45. package/dist/measure.js +3 -0
  46. package/dist/node.d.ts +12 -0
  47. package/dist/node.d.ts.map +1 -0
  48. package/dist/node.js +60 -0
  49. package/dist/node.js.map +1 -0
  50. package/dist/package-CaOLXSNi.d.ts +193 -0
  51. package/dist/package-CaOLXSNi.d.ts.map +1 -0
  52. package/dist/pres-5x1bjCzk.d.ts +202 -0
  53. package/dist/pres-5x1bjCzk.d.ts.map +1 -0
  54. package/dist/presentation-B0JWdTN1.js +4286 -0
  55. package/dist/presentation-B0JWdTN1.js.map +1 -0
  56. package/dist/presentation-RGOiun5P.d.ts +3249 -0
  57. package/dist/presentation-RGOiun5P.d.ts.map +1 -0
  58. package/dist/presentation-types-BVw0EknS.d.ts +538 -0
  59. package/dist/presentation-types-BVw0EknS.d.ts.map +1 -0
  60. package/dist/read.d.ts +73 -0
  61. package/dist/read.d.ts.map +1 -0
  62. package/dist/read.js +4 -0
  63. package/dist/script.d.ts +553 -0
  64. package/dist/script.d.ts.map +1 -0
  65. package/dist/script.js +0 -0
  66. package/dist/script.js.map +1 -0
  67. package/dist/shapes-BZU8UTW2.js +5365 -0
  68. package/dist/shapes-BZU8UTW2.js.map +1 -0
  69. package/dist/slide-B6mDaM-P.d.ts +3396 -0
  70. package/dist/slide-B6mDaM-P.d.ts.map +1 -0
  71. package/dist/text-WRUbOy2r.js +11238 -0
  72. package/dist/text-WRUbOy2r.js.map +1 -0
  73. package/dist/units-B-JUKwCS.js +144 -0
  74. package/dist/units-B-JUKwCS.js.map +1 -0
  75. package/dist/units-internal-7JcMfYti.js +723 -0
  76. package/dist/units-internal-7JcMfYti.js.map +1 -0
  77. package/dist/zip.d.ts +68 -0
  78. package/dist/zip.d.ts.map +1 -0
  79. package/dist/zip.js +163 -0
  80. package/dist/zip.js.map +1 -0
  81. package/package.json +214 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2022 Brent Ely
4
+ Copyright (c) 2026 shbernal
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # ts-pptx
2
+
3
+ [![npm](https://img.shields.io/npm/v/@shbernal/ts-pptx)](https://www.npmjs.com/package/@shbernal/ts-pptx)
4
+ [![CI](https://github.com/shbernal/ts-pptx/actions/workflows/ci.yml/badge.svg)](https://github.com/shbernal/ts-pptx/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ ts-pptx generates PowerPoint `.pptx` files from TypeScript and modern
8
+ JavaScript. This project targets ESM package consumers, typed application code,
9
+ reproducible package verification, and agent-assisted OOXML development.
10
+
11
+ > **Lineage.** ts-pptx descends from [gitbrent/PptxGenJS](https://github.com/gitbrent/PptxGenJS)
12
+ > (MIT), detached at its v6.0.0 (June 2025) and developed independently since. It
13
+ > does not track, merge from, or mirror the original project, and pursues its own
14
+ > Node-first direction (see _Project Target_). The original work remains under its
15
+ > MIT license — see _License_ below.
16
+
17
+ ## Project Target
18
+
19
+ - Generate standards-based PowerPoint `.pptx` packages without requiring
20
+ PowerPoint at runtime.
21
+ - Support TypeScript-first workflows with checked declarations and modern
22
+ bundler resolution.
23
+ - Ship a small, explicit ESM package boundary for Node.js, Vite, React,
24
+ Angular, Electron, and similar modern toolchains.
25
+ - Keep OOXML changes grounded in fixtures, schema validation, and PowerPoint
26
+ compatibility evidence.
27
+ - Make the repository practical for human and agent-driven maintenance.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ pnpm add @shbernal/ts-pptx
33
+ ```
34
+
35
+ ```bash
36
+ npm install @shbernal/ts-pptx
37
+ ```
38
+
39
+ ```bash
40
+ yarn add @shbernal/ts-pptx
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```ts
46
+ import TsPptx from "@shbernal/ts-pptx"
47
+
48
+ const pptx = new TsPptx()
49
+ const slide = pptx.addSlide()
50
+
51
+ slide.addText("Hello from ts-pptx", {
52
+ x: 1,
53
+ y: 1,
54
+ w: 8,
55
+ h: 1,
56
+ fontSize: 24,
57
+ color: "363636",
58
+ })
59
+
60
+ await pptx.writeFile({ fileName: "example.pptx" })
61
+ ```
62
+
63
+ ## What It Can Generate
64
+
65
+ - Slides, layouts, masters, sections, notes, and metadata.
66
+ - Text, tables, shapes, images, SVGs, charts, and media.
67
+ - Browser-downloadable, streamed, buffered, Blob, base64, or file outputs,
68
+ depending on the runtime.
69
+ - OOXML that is intended to open cleanly in Microsoft PowerPoint and other
70
+ `.pptx` consumers such as Keynote, LibreOffice Impress, and Google Slides
71
+ import.
72
+
73
+ ## Scope And Contributions
74
+
75
+ This project is **Node-first**: it generates and is tested without a browser or any
76
+ office application. Two areas are out of *active* maintenance scope — not because
77
+ they lack merit, but because there is no in-house use case driving them, so the
78
+ maintainer generally will not pick up bugs or feature requests there:
79
+
80
+ - **Live-DOM / browser-layout features** — anything whose answer comes from a
81
+ *rendered* page: real `offsetWidth` after layout, the resolved cascade, fonts as
82
+ the browser actually chose them. (Converting an HTML `<table>` is *not* in this
83
+ category — see [HTML tables → slides](#html-tables--slides) below. Only real
84
+ measurement needs a browser.)
85
+ - **Third-party office-suite interop quirks** that appear only after a file is
86
+ round-tripped through another application (for example, copy/paste inside WPS
87
+ Office, then opening in PowerPoint) when the generated package is itself valid
88
+ OOXML. The supported bar is that output opens cleanly in Microsoft PowerPoint.
89
+
90
+ **Contributions in these areas are welcome** — issues and pull requests are
91
+ encouraged even though the maintainer is not actively developing them. See
92
+ [`docs/project-target.md`](docs/project-target.md) for the full scope statement
93
+ and suggested testing approaches.
94
+
95
+ ## Runtime And Package Support
96
+
97
+ The package is ESM-only.
98
+
99
+ Supported package surface:
100
+
101
+ - `import TsPptx, { ShapeType } from "@shbernal/ts-pptx"` (enums, shared types, and
102
+ layout helpers ship from the main entry)
103
+ - `import { inspectPptx } from "@shbernal/ts-pptx/inspect"`
104
+ - `import { measureText } from "@shbernal/ts-pptx/measure"`
105
+ - `import { Presentation } from "@shbernal/ts-pptx/read"`
106
+ - `import { latexToOmml } from "@shbernal/ts-pptx/math"`
107
+ - `import { tableToSlides } from "@shbernal/ts-pptx/html"`
108
+ - `import TsPptx from "@shbernal/ts-pptx/node"`
109
+ - `import TsPptx from "@shbernal/ts-pptx/browser"`
110
+ — the bare specifier resolves to one of these two by export condition, so Node
111
+ and bundled browser apps get the right build without naming it. A runtime that
112
+ sets neither (Deno, Bun, edge workers) gets a runtime-agnostic build that
113
+ authors and exports bytes normally but has no `writeFile` destination; see
114
+ [Runtime And Package Support](docs/runtime-and-package-support.md#which-build-the-bare-import-gives-you).
115
+ - generated runtime and declaration artifacts under `dist/`
116
+ - Node.js `>=24`
117
+ - modern bundlers and module-aware app frameworks
118
+
119
+ Deliberately not supported:
120
+
121
+ - No CommonJS: no `require("@shbernal/ts-pptx")`, no CJS export condition, and no
122
+ `.cjs` artifact. Modern Node.js may provide `require()` interop for ESM, but it
123
+ is not a maintained API.
124
+ - No IIFE/global browser bundle: no classic-script global, no `dist/*.bundle.js`,
125
+ and no `dist/*.min.js`.
126
+
127
+ Use the package exports rather than direct `dist/` artifact paths.
128
+
129
+ See [runtime and package support](docs/runtime-and-package-support.md) for the
130
+ complete support contract.
131
+
132
+ ## HTML Tables → Slides
133
+
134
+ `@shbernal/ts-pptx/html` reproduces an existing HTML `<table>` as a PowerPoint
135
+ table, auto-paging across as many slides as its rows need. It works in the
136
+ browser and under Node with any DOM implementation, from one artifact.
137
+
138
+ ```ts
139
+ import { TsPptx } from '@shbernal/ts-pptx'
140
+ import { tableToSlides } from '@shbernal/ts-pptx/html'
141
+ import { Window } from 'happy-dom'
142
+
143
+ const win = new Window()
144
+ win.document.body.innerHTML = '<table id="report">…</table>'
145
+
146
+ const pptx = new TsPptx()
147
+ tableToSlides(pptx, win.document.getElementById('report'))
148
+ await pptx.writeFile({ fileName: 'report.pptx' })
149
+ ```
150
+
151
+ Pass the element itself and no global DOM is consulted at all. To pass a string
152
+ id instead, say which document it belongs to:
153
+
154
+ ```ts
155
+ tableToSlides(pptx, 'report', { document: win.document })
156
+ ```
157
+
158
+ In a browser, `options.document` defaults to the global `document`, so
159
+ `tableToSlides(pptx, 'report')` is enough. The equivalent method form,
160
+ `pptx.tableToSlides('report', options)`, remains on the browser build and
161
+ delegates to the same implementation.
162
+
163
+ **Column widths need a layout engine.** In a browser the columns are sized from
164
+ each cell's rendered `offsetWidth`, reproducing the table's real proportions.
165
+ Nothing outside a browser lays a table out, so `offsetWidth` is `0` there and
166
+ the conversion degrades in two steps: it uses the computed CSS `width`s when the
167
+ stylesheet states them for every column in one unit (all `px` or all `%`), and
168
+ an equal split when it does not.
169
+
170
+ To pin widths regardless of runtime, annotate the `<thead>` header cells — these
171
+ win outright on every path:
172
+
173
+ ```html
174
+ <thead>
175
+ <tr>
176
+ <th data-pptx-width="2.5">Name</th>
177
+ <th data-pptx-min-width="1">Qty</th>
178
+ </tr>
179
+ </thead>
180
+ ```
181
+
182
+ Everything else behaves the same wherever it runs: cell text (with `<br>` kept
183
+ as a line break), `colspan`/`rowspan`, computed colors, weight, alignment,
184
+ padding and borders, and auto-paging.
185
+
186
+ ## Documentation
187
+
188
+ The full documentation site is published at
189
+ **<https://shbernal.github.io/ts-pptx/>**, including the generated API reference.
190
+
191
+ - [Documentation index](docs/README.md)
192
+ - [Project target](docs/project-target.md)
193
+ - [Runtime and package support](docs/runtime-and-package-support.md)
194
+ - [Development guide](docs/development.md)
195
+ - [Testing guide](docs/testing.md)
196
+ - [Agent development guide](docs/agent-development.md)
197
+ - [OOXML agent context](docs/ooxml-agent-context.md)
198
+ - [Backlog workflow](docs/backlog-workflow.md)
199
+
200
+ ## Repository Development
201
+
202
+ This repository uses `pnpm` and requires Node.js `>=24`.
203
+
204
+ ```bash
205
+ pnpm install
206
+ pnpm run verify
207
+ ```
208
+
209
+ OOXML serialization changes should also add or update a schema fixture in
210
+ `test/schema-cases.js`. The schema suite needs the validator installed once:
211
+
212
+ ```bash
213
+ ./tools/ooxml-validator/install.sh
214
+ ```
215
+
216
+ Package-boundary changes should run:
217
+
218
+ ```bash
219
+ pnpm run check:package
220
+ ```
221
+
222
+ ## Demos
223
+
224
+ - `demos/node` exercises Node.js ESM generation and stream output.
225
+ - `demos/vite-demo` exercises a modern React, TypeScript, and Vite app.
226
+
227
+ ## Relationship To Upstream
228
+
229
+ ts-pptx builds on the original work of Brent Ely and the gitbrent/PptxGenJS
230
+ contributors. The modernized package target is intentionally narrower than the
231
+ original in order to simplify the runtime contract and keep maintenance focused.
232
+
233
+ ## License
234
+
235
+ Copyright (c) 2015-2022 Brent Ely.
236
+ Modifications copyright (c) 2026 shbernal.
237
+
238
+ [MIT](LICENSE)
@@ -0,0 +1,420 @@
1
+ import { n as warn } from "./diagnostics-DYQC7xLV.js";
2
+ import { i as EMU_PER_POINT, r as EMU_PER_INCH } from "./units-B-JUKwCS.js";
3
+ import { E as DEF_SLIDE_MARGIN_IN, P as LINEH_MODIFIER, i as inch2Emu, o as marginToEmu, r as getSmartParseNumber } from "./units-internal-7JcMfYti.js";
4
+ //#region src/gen/table/autopage.ts
5
+ /**
6
+ * Break cell text into lines based upon table column width (e.g.: Magic Happens Here(tm))
7
+ * @param {TableCell} cell - table cell
8
+ * @param {number} colWidth - table column width (inches)
9
+ * @return {TableRow[]} - cell's text objects grouped into lines
10
+ */
11
+ function parseTextToLines(cell, colWidth, verbose) {
12
+ const FOCO = 2.3 + (cell.options?.autoPageCharWeight ? cell.options.autoPageCharWeight : 0);
13
+ const CPL = Math.floor(colWidth / EMU_PER_POINT * EMU_PER_INCH) / ((cell.options?.fontSize ? cell.options.fontSize : 12) / FOCO);
14
+ const parsedLines = [];
15
+ let inputCells = [];
16
+ const inputLines1 = [];
17
+ const inputLines2 = [];
18
+ /**
19
+ * EX INPUTS: `cell.text`
20
+ * - string....: "Account Name Column"
21
+ * - object....: { text:"Account Name Column" }
22
+ * - object[]..: [{ text:"Account Name", options:{ bold:true } }, { text:" Column" }]
23
+ * - object[]..: [{ text:"Account Name", options:{ breakLine:true } }, { text:"Input" }]
24
+ */
25
+ /**
26
+ * EX OUTPUTS:
27
+ * - string....: [{ text:"Account Name Column" }]
28
+ * - object....: [{ text:"Account Name Column" }]
29
+ * - object[]..: [{ text:"Account Name", options:{ breakLine:true } }, { text:"Input" }]
30
+ * - object[]..: [{ text:"Account Name", options:{ breakLine:true } }, { text:"Input" }]
31
+ */
32
+ if (cell.text && cell.text.toString().trim().length === 0) inputCells.push({
33
+ _type: "tablecell",
34
+ text: " "
35
+ });
36
+ else if (typeof cell.text === "number" || typeof cell.text === "string") inputCells.push({
37
+ _type: "tablecell",
38
+ text: (cell.text || "").toString().trim()
39
+ });
40
+ else if (Array.isArray(cell.text)) inputCells = cell.text;
41
+ if (verbose) {
42
+ console.log("[1/4] inputCells");
43
+ inputCells.forEach((cell, idx) => console.log(`[1/4] [${idx + 1}] cell: ${JSON.stringify(cell)}`));
44
+ }
45
+ /**
46
+ * - EX: `[{ text:"Input Output" }, { text:"Extra" }]` == 1 line
47
+ * - EX: `[{ text:"Input" }, { text:"Output", options:{ breakLine:true } }]` == 1 line
48
+ * - EX: `[{ text:"Input\nOutput" }]` == 2 lines
49
+ * - EX: `[{ text:"Input", options:{ breakLine:true } }, { text:"Output" }]` == 2 lines
50
+ */
51
+ let newLine = [];
52
+ inputCells.forEach((cell) => {
53
+ if (typeof cell.text !== "string") return;
54
+ if (cell.text.includes("\n")) {
55
+ const parts = cell.text.split("\n");
56
+ parts.forEach((part, partIdx) => {
57
+ if (partIdx === parts.length - 1) newLine.push({
58
+ _type: "tablecell",
59
+ text: part,
60
+ options: cell.options
61
+ });
62
+ else {
63
+ newLine.push({
64
+ _type: "tablecell",
65
+ text: part,
66
+ options: {
67
+ ...cell.options,
68
+ breakLine: true
69
+ }
70
+ });
71
+ inputLines1.push(newLine);
72
+ newLine = [];
73
+ }
74
+ });
75
+ } else newLine.push({
76
+ _type: "tablecell",
77
+ text: cell.text.trim(),
78
+ options: cell.options
79
+ });
80
+ if (cell.options?.breakLine) {
81
+ if (verbose) console.log(`inputCells: new line > ${JSON.stringify(newLine)}`);
82
+ inputLines1.push(newLine);
83
+ newLine = [];
84
+ }
85
+ });
86
+ if (newLine.length > 0) {
87
+ inputLines1.push(newLine);
88
+ newLine = [];
89
+ }
90
+ if (verbose) {
91
+ console.log(`[2/4] inputLines1 (${inputLines1.length})`);
92
+ inputLines1.forEach((line, idx) => console.log(`[2/4] [${idx + 1}] line: ${JSON.stringify(line)}`));
93
+ }
94
+ inputLines1.forEach((line) => {
95
+ const lineTokens = [];
96
+ line.forEach((cell) => {
97
+ const lineWords = String(cell.text).split(" ");
98
+ lineWords.forEach((word, idx) => {
99
+ const cellProps = { ...cell.options };
100
+ if (cellProps?.breakLine) cellProps.breakLine = idx + 1 === lineWords.length;
101
+ lineTokens.push({
102
+ _type: "tablecell",
103
+ text: word + (idx + 1 < lineWords.length ? " " : ""),
104
+ options: cellProps
105
+ });
106
+ });
107
+ });
108
+ inputLines2.push(lineTokens);
109
+ });
110
+ if (verbose) {
111
+ console.log(`[3/4] inputLines2 (${inputLines2.length})`);
112
+ inputLines2.forEach((line) => console.log(`[3/4] line: ${JSON.stringify(line)}`));
113
+ }
114
+ inputLines2.forEach((line) => {
115
+ let lineCells = [];
116
+ let strCurrLine = "";
117
+ line.forEach((word) => {
118
+ const wordText = String(word.text || "");
119
+ if (strCurrLine.length + wordText.length > CPL) {
120
+ parsedLines.push(lineCells);
121
+ lineCells = [];
122
+ strCurrLine = "";
123
+ }
124
+ lineCells.push(word);
125
+ strCurrLine += wordText;
126
+ });
127
+ if (lineCells.length > 0) parsedLines.push(lineCells);
128
+ });
129
+ if (verbose) {
130
+ console.log(`[4/4] parsedLines (${parsedLines.length})`);
131
+ parsedLines.forEach((line, idx) => console.log(`[4/4] [Line ${idx + 1}]:\n${JSON.stringify(line)}`));
132
+ console.log("...............................................\n\n");
133
+ }
134
+ return parsedLines;
135
+ }
136
+ /**
137
+ * Takes an array of table rows and breaks into an array of slides, which contain the calculated amount of table rows that fit on that slide
138
+ * @param {TableCell[][]} tableRows - table rows
139
+ * @param {TableToSlidesProps} tableProps - table2slides properties
140
+ * @param {PresLayout} presLayout - presentation layout
141
+ * @param {SlideLayoutInternal} masterSlide - master slide
142
+ * @return {TableRowSlide[]} array of table rows
143
+ */
144
+ function getSlidesForTableRows(tableRows = [], tableProps = {}, presLayout, masterSlide) {
145
+ let arrInchMargins = DEF_SLIDE_MARGIN_IN;
146
+ let emuSlideTabW;
147
+ let emuSlideTabH = EMU_PER_INCH * 1;
148
+ let emuTabCurrH = 0;
149
+ let numCols = 0;
150
+ let warnedNoTabH = false;
151
+ const tableRowSlides = [];
152
+ const tablePropX = getSmartParseNumber(tableProps.x, "X", presLayout);
153
+ const tablePropY = getSmartParseNumber(tableProps.y, "Y", presLayout);
154
+ const tablePropW = getSmartParseNumber(tableProps.w, "X", presLayout);
155
+ const tablePropH = getSmartParseNumber(tableProps.h, "Y", presLayout);
156
+ let tableCalcW = tablePropW;
157
+ function calcSlideTabH() {
158
+ let emuStartY = 0;
159
+ if (tableRowSlides.length === 0) emuStartY = tablePropY || inch2Emu(arrInchMargins[0]);
160
+ if (tableRowSlides.length > 0) emuStartY = inch2Emu(tableProps.autoPageSlideStartY || arrInchMargins[0]);
161
+ emuSlideTabH = (tablePropH || presLayout.height) - emuStartY - inch2Emu(arrInchMargins[2]);
162
+ if (tableRowSlides.length === 0 && tablePropH && emuSlideTabH < tablePropH) emuSlideTabH = tablePropH;
163
+ if (tableRowSlides.length > 1) {
164
+ if (typeof tableProps.autoPageSlideStartY === "number") emuSlideTabH = (tablePropH || presLayout.height) - inch2Emu(tableProps.autoPageSlideStartY + arrInchMargins[2]);
165
+ else if (tablePropY) {
166
+ emuSlideTabH = (tablePropH || presLayout.height) - inch2Emu((tablePropY / 914400 < arrInchMargins[0] ? tablePropY / EMU_PER_INCH : arrInchMargins[0]) + arrInchMargins[2]);
167
+ if (emuSlideTabH < tablePropH) emuSlideTabH = tablePropH;
168
+ }
169
+ }
170
+ const emuBaseLineH = inch2Emu((typeof tableProps.fontSize === "number" ? tableProps.fontSize : 12) * (LINEH_MODIFIER + (tableProps.autoPageLineWeight || 0)) / 100);
171
+ if (emuSlideTabH < emuBaseLineH) {
172
+ const emuStartY = tableRowSlides.length === 0 ? tablePropY || inch2Emu(arrInchMargins[0]) : inch2Emu(tableProps.autoPageSlideStartY || arrInchMargins[0]);
173
+ const fallbackH = presLayout.height - emuStartY - inch2Emu(arrInchMargins[2]);
174
+ if (!warnedNoTabH) {
175
+ warn("table/autopage-height-too-small", "addTable/autoPage: the table height (`h`) leaves no room to paginate; ignoring it and using the slide height. Increase `h` or decrease `y`.");
176
+ warnedNoTabH = true;
177
+ }
178
+ emuSlideTabH = fallbackH > 0 ? fallbackH : presLayout.height;
179
+ }
180
+ }
181
+ if (tableProps.verbose) {
182
+ console.log("[[VERBOSE MODE]]");
183
+ console.log("|-- TABLE PROPS --------------------------------------------------------|");
184
+ console.log(`| presLayout.width ................................ = ${(presLayout.width / EMU_PER_INCH).toFixed(1)}`);
185
+ console.log(`| presLayout.height ............................... = ${(presLayout.height / EMU_PER_INCH).toFixed(1)}`);
186
+ console.log(`| tableProps.x .................................... = ${typeof tableProps.x === "number" ? (tableProps.x / EMU_PER_INCH).toFixed(1) : tableProps.x}`);
187
+ console.log(`| tableProps.y .................................... = ${typeof tableProps.y === "number" ? (tableProps.y / EMU_PER_INCH).toFixed(1) : tableProps.y}`);
188
+ console.log(`| tableProps.w .................................... = ${typeof tableProps.w === "number" ? (tableProps.w / EMU_PER_INCH).toFixed(1) : tableProps.w}`);
189
+ console.log(`| tableProps.h .................................... = ${typeof tableProps.h === "number" ? (tableProps.h / EMU_PER_INCH).toFixed(1) : tableProps.h}`);
190
+ console.log(`| tableProps.slideMargin .......................... = ${tableProps.slideMargin ? String(tableProps.slideMargin) : ""}`);
191
+ console.log(`| tableProps.margin ............................... = ${String(tableProps.margin)}`);
192
+ console.log(`| tableProps.colW ................................. = ${String(tableProps.colW)}`);
193
+ console.log(`| tableProps.autoPageSlideStartY .................. = ${tableProps.autoPageSlideStartY}`);
194
+ console.log(`| tableProps.autoPageCharWeight ................... = ${tableProps.autoPageCharWeight}`);
195
+ console.log("|-- CALCULATIONS -------------------------------------------------------|");
196
+ console.log(`| tablePropX ...................................... = ${tablePropX / EMU_PER_INCH}`);
197
+ console.log(`| tablePropY ...................................... = ${tablePropY / EMU_PER_INCH}`);
198
+ console.log(`| tablePropW ...................................... = ${tablePropW / EMU_PER_INCH}`);
199
+ console.log(`| tablePropH ...................................... = ${tablePropH / EMU_PER_INCH}`);
200
+ console.log(`| tableCalcW ...................................... = ${tableCalcW / EMU_PER_INCH}`);
201
+ }
202
+ if (!tableProps.slideMargin && tableProps.slideMargin !== 0) tableProps.slideMargin = DEF_SLIDE_MARGIN_IN[0];
203
+ if (masterSlide && typeof masterSlide._margin !== "undefined") {
204
+ if (Array.isArray(masterSlide._margin)) arrInchMargins = masterSlide._margin;
205
+ else if (!isNaN(Number(masterSlide._margin))) arrInchMargins = [
206
+ Number(masterSlide._margin),
207
+ Number(masterSlide._margin),
208
+ Number(masterSlide._margin),
209
+ Number(masterSlide._margin)
210
+ ];
211
+ } else if (tableProps.slideMargin || tableProps.slideMargin === 0) {
212
+ if (Array.isArray(tableProps.slideMargin)) arrInchMargins = tableProps.slideMargin;
213
+ else if (!isNaN(tableProps.slideMargin)) arrInchMargins = [
214
+ tableProps.slideMargin,
215
+ tableProps.slideMargin,
216
+ tableProps.slideMargin,
217
+ tableProps.slideMargin
218
+ ];
219
+ }
220
+ if (tableProps.verbose) console.log(`| arrInchMargins .................................. = [${arrInchMargins.join(", ")}]`);
221
+ (tableRows[0] || []).forEach((cell) => {
222
+ if (!cell) cell = { _type: "tablecell" };
223
+ const cellOpts = cell.options || null;
224
+ numCols += Number(cellOpts?.colspan ? cellOpts.colspan : 1);
225
+ });
226
+ if (tableProps.verbose) console.log(`| numCols ......................................... = ${numCols}`);
227
+ const colSpanDepths = new Array(numCols).fill(0);
228
+ if (!tablePropW && tableProps.colW) {
229
+ tableCalcW = Array.isArray(tableProps.colW) ? tableProps.colW.reduce((p, n) => p + n) * EMU_PER_INCH : tableProps.colW * numCols || 0;
230
+ if (tableProps.verbose) console.log(`| tableCalcW ...................................... = ${tableCalcW / EMU_PER_INCH}`);
231
+ }
232
+ emuSlideTabW = tableCalcW || inch2Emu((tablePropX ? tablePropX / 914400 : arrInchMargins[1]) + arrInchMargins[3]);
233
+ if (tableProps.verbose) console.log(`| emuSlideTabW .................................... = ${(emuSlideTabW / EMU_PER_INCH).toFixed(1)}`);
234
+ if (!tableProps.colW || !Array.isArray(tableProps.colW)) if (tableProps.colW && !isNaN(Number(tableProps.colW))) {
235
+ const arrColW = [];
236
+ const colW = Number(tableProps.colW);
237
+ (tableRows[0] || []).forEach(() => arrColW.push(colW));
238
+ tableProps.colW = [];
239
+ arrColW.forEach((val) => {
240
+ if (Array.isArray(tableProps.colW)) tableProps.colW.push(val);
241
+ });
242
+ } else {
243
+ tableProps.colW = [];
244
+ for (let iCol = 0; iCol < numCols; iCol++) tableProps.colW.push(emuSlideTabW / EMU_PER_INCH / numCols);
245
+ }
246
+ const resolveRowH = (origRowIdx) => Array.isArray(tableProps.rowH) && typeof tableProps.rowH[origRowIdx] === "number" ? tableProps.rowH[origRowIdx] : void 0;
247
+ let newTableRowSlide = {
248
+ rows: [],
249
+ rowH: []
250
+ };
251
+ tableRows.forEach((row, iRow) => {
252
+ const hasActiveRowSpan = colSpanDepths.some((d) => d > 0);
253
+ const rowCellLines = [];
254
+ let maxCellMarTopEmu = 0;
255
+ let maxCellMarBtmEmu = 0;
256
+ let currTableRow = [];
257
+ row.forEach((cell) => {
258
+ currTableRow.push({
259
+ _type: "tablecell",
260
+ text: [],
261
+ options: cell.options
262
+ });
263
+ const cellMargin = Array.isArray(cell.options?.margin) ? cell.options.margin : void 0;
264
+ const tableMargin = Array.isArray(tableProps.margin) ? tableProps.margin : null;
265
+ if (cellMargin?.[0] && marginToEmu(cellMargin[0]) > maxCellMarTopEmu) maxCellMarTopEmu = marginToEmu(cellMargin[0]);
266
+ else if (tableMargin?.[0] && marginToEmu(tableMargin[0]) > maxCellMarTopEmu) maxCellMarTopEmu = marginToEmu(tableMargin[0]);
267
+ if (cellMargin?.[2] && marginToEmu(cellMargin[2]) > maxCellMarBtmEmu) maxCellMarBtmEmu = marginToEmu(cellMargin[2]);
268
+ else if (tableMargin?.[2] && marginToEmu(tableMargin[2]) > maxCellMarBtmEmu) maxCellMarBtmEmu = marginToEmu(tableMargin[2]);
269
+ });
270
+ calcSlideTabH();
271
+ emuTabCurrH += maxCellMarTopEmu + maxCellMarBtmEmu;
272
+ if (tableProps.verbose && iRow === 0) console.log(`| SLIDE [${tableRowSlides.length}]: emuSlideTabH ...... = ${(emuSlideTabH / EMU_PER_INCH).toFixed(1)} `);
273
+ row.forEach((cell, iCell) => {
274
+ const newCellOptions = cell.options || {};
275
+ const newCell = {
276
+ _type: "tablecell",
277
+ _lines: [],
278
+ _lineHeight: inch2Emu((cell.options?.fontSize ? cell.options.fontSize : tableProps.fontSize ? tableProps.fontSize : 12) * (LINEH_MODIFIER + (tableProps.autoPageLineWeight ? tableProps.autoPageLineWeight : 0)) / 100),
279
+ text: [],
280
+ options: newCellOptions
281
+ };
282
+ if (newCellOptions.rowspan) newCell._lineHeight = 0;
283
+ newCellOptions.autoPageCharWeight = tableProps.autoPageCharWeight || void 0;
284
+ const tableColW = Array.isArray(tableProps.colW) ? tableProps.colW : [];
285
+ let totalColW = tableColW[iCell] ?? 0;
286
+ const cellColspan = cell.options?.colspan;
287
+ if (cellColspan) totalColW = tableColW.filter((_cell, idx) => idx >= iCell && idx < idx + cellColspan).reduce((prev, curr) => prev + curr);
288
+ newCell._lines = parseTextToLines(cell, totalColW, false);
289
+ rowCellLines.push(newCell);
290
+ });
291
+ /** E: --==[[ PAGE DATA SET ]]==--
292
+ * Add text one-line-a-time to this row's cells until: lines are exhausted OR table height limit is hit
293
+ *
294
+ * Design:
295
+ * - Building cells L-to-R/loop style wont work as one could be 100 lines and another 1 line
296
+ * - Therefore, build the whole row, one-line-at-a-time, across each table columns
297
+ * - Then, when the vertical size limit is hit is by any of the cells, make a new slide and continue adding any remaining lines
298
+ *
299
+ * Implementation:
300
+ * - `rowCellLines` is an array of cells, one for each column in the table, with each cell containing an array of lines
301
+ *
302
+ * Sample Data:
303
+ * - `rowCellLines` ..: [ TableCell, TableCell, TableCell ]
304
+ * - `TableCell` .....: { _type: 'tablecell', _lines: TableCell[], _lineHeight: 10 }
305
+ * - `_lines` ........: [ {_type: 'tablecell', text: 'cell-1,line-1', options: {…}}, {_type: 'tablecell', text: 'cell-1,line-2', options: {…}} }
306
+ * - `_lines` is TableCell[] (the 1-N words in the line)
307
+ * {
308
+ * _lines: [{ text:'cell-1,line-1' }, { text:'cell-1,line-2' }], // TOTAL-CELL-HEIGHT = 2
309
+ * _lines: [{ text:'cell-2,line-1' }, { text:'cell-2,line-2' }], // TOTAL-CELL-HEIGHT = 2
310
+ * _lines: [{ text:'cell-3,line-1' }, { text:'cell-3,line-2' }, { text:'cell-3,line-3' }, { text:'cell-3,line-4' }], // TOTAL-CELL-HEIGHT = 4
311
+ * }
312
+ *
313
+ * Example: 2 rows, with the firstrow overflowing onto a new slide
314
+ * SLIDE 1:
315
+ * |--------|--------|--------|--------|
316
+ * | line-1 | line-1 | line-1 | line-1 |
317
+ * | | | line-2 | |
318
+ * | | | line-3 | |
319
+ * |--------|--------|--------|--------|
320
+ *
321
+ * SLIDE 2:
322
+ * |--------|--------|--------|--------|
323
+ * | | | line-4 | |
324
+ * |--------|--------|--------|--------|
325
+ * | line-1 | line-1 | line-1 | line-1 |
326
+ * |--------|--------|--------|--------|
327
+ */
328
+ if (tableProps.verbose) console.log(`\n| SLIDE [${tableRowSlides.length}]: ROW [${iRow}]: START...`);
329
+ let currCellIdx = 0;
330
+ let emuLineMaxH = 0;
331
+ let isDone = false;
332
+ while (!isDone) {
333
+ const srcCell = rowCellLines[currCellIdx];
334
+ if (!srcCell) break;
335
+ let tgtCell = currTableRow[currCellIdx];
336
+ rowCellLines.forEach((cell) => {
337
+ if (cell._lineHeight >= emuLineMaxH) emuLineMaxH = cell._lineHeight;
338
+ });
339
+ if (emuTabCurrH + emuLineMaxH > emuSlideTabH && !hasActiveRowSpan) {
340
+ if (tableProps.verbose) {
341
+ console.log("\n|-----------------------------------------------------------------------|");
342
+ console.log(`|-- NEW SLIDE CREATED (currTabH+currLineH > maxH) => ${(emuTabCurrH / EMU_PER_INCH).toFixed(2)} + ${(srcCell._lineHeight / EMU_PER_INCH).toFixed(2)} > ${emuSlideTabH / EMU_PER_INCH}`);
343
+ console.log("|-----------------------------------------------------------------------|\n\n");
344
+ }
345
+ if (currTableRow.length > 0 && currTableRow.map((cell) => Array.isArray(cell.text) ? cell.text.length : 0).reduce((p, n) => p + n) > 0) {
346
+ newTableRowSlide.rows.push(currTableRow);
347
+ newTableRowSlide.rowH?.push(resolveRowH(iRow));
348
+ }
349
+ if (newTableRowSlide.rows.length > 0) tableRowSlides.push(newTableRowSlide);
350
+ newTableRowSlide = {
351
+ rows: [],
352
+ rowH: []
353
+ };
354
+ currTableRow = [];
355
+ row.forEach((cell) => currTableRow.push({
356
+ _type: "tablecell",
357
+ text: [],
358
+ options: cell.options
359
+ }));
360
+ calcSlideTabH();
361
+ emuTabCurrH += maxCellMarTopEmu + maxCellMarBtmEmu;
362
+ if (tableProps.verbose) console.log(`| SLIDE [${tableRowSlides.length}]: emuSlideTabH ...... = ${(emuSlideTabH / EMU_PER_INCH).toFixed(1)} `);
363
+ emuTabCurrH = 0;
364
+ if (tableProps.autoPageRepeatHeader && tableProps._arrObjTabHeadRows) tableProps._arrObjTabHeadRows.forEach((row, headIdx) => {
365
+ const newHeadRow = [];
366
+ let maxLineHeight = 0;
367
+ row.forEach((cell) => {
368
+ newHeadRow.push(cell);
369
+ if ((cell._lineHeight || 0) > maxLineHeight) maxLineHeight = cell._lineHeight || 0;
370
+ });
371
+ newTableRowSlide.rows.push(newHeadRow);
372
+ newTableRowSlide.rowH?.push(resolveRowH(headIdx));
373
+ emuTabCurrH += maxLineHeight;
374
+ });
375
+ tgtCell = currTableRow[currCellIdx];
376
+ }
377
+ const currLine = srcCell._lines.shift();
378
+ if (tgtCell && Array.isArray(tgtCell.text)) {
379
+ if (currLine) tgtCell.text = tgtCell.text.concat(currLine);
380
+ else if (tgtCell.text.length === 0) tgtCell.text = tgtCell.text.concat({
381
+ _type: "tablecell",
382
+ text: ""
383
+ });
384
+ }
385
+ if (currCellIdx === rowCellLines.length - 1) emuTabCurrH += emuLineMaxH;
386
+ currCellIdx = currCellIdx < rowCellLines.length - 1 ? currCellIdx + 1 : 0;
387
+ if (rowCellLines.map((cell) => cell._lines.length).reduce((prev, next) => prev + next) === 0) isDone = true;
388
+ }
389
+ if (currTableRow.length > 0) {
390
+ newTableRowSlide.rows.push(currTableRow);
391
+ newTableRowSlide.rowH?.push(resolveRowH(iRow));
392
+ }
393
+ const occupiedBefore = [...colSpanDepths];
394
+ let colCursor = 0;
395
+ row.forEach((cell) => {
396
+ while (colCursor < numCols && (occupiedBefore[colCursor] ?? 0) > 0) colCursor++;
397
+ const cellColspan = cell.options?.colspan ?? 1;
398
+ const cellRowspan = cell.options?.rowspan ?? 1;
399
+ if (cellRowspan > 1) for (let c = 0; c < cellColspan && colCursor + c < numCols; c++) colSpanDepths[colCursor + c] = cellRowspan;
400
+ colCursor += cellColspan;
401
+ });
402
+ for (let c = 0; c < numCols; c++) {
403
+ const depth = colSpanDepths[c] ?? 0;
404
+ if (depth > 0) colSpanDepths[c] = depth - 1;
405
+ }
406
+ if (tableProps.verbose) console.log(`- SLIDE [${tableRowSlides.length}]: ROW [${iRow}]: ...COMPLETE ...... emuTabCurrH = ${(emuTabCurrH / EMU_PER_INCH).toFixed(2)} ( emuSlideTabH = ${(emuSlideTabH / EMU_PER_INCH).toFixed(2)} )`);
407
+ });
408
+ if (newTableRowSlide.rows.length > 0 || tableRowSlides.length === 0) tableRowSlides.push(newTableRowSlide);
409
+ if (tableProps.verbose) {
410
+ console.log("\n|================================================|");
411
+ console.log(`| FINAL: tableRowSlides.length = ${tableRowSlides.length}`);
412
+ tableRowSlides.forEach((slide) => console.log(slide));
413
+ console.log("|================================================|\n\n");
414
+ }
415
+ return tableRowSlides;
416
+ }
417
+ //#endregion
418
+ export { getSlidesForTableRows as t };
419
+
420
+ //# sourceMappingURL=autopage-tmfjRzL4.js.map