pptx-ts 3.7.0 → 4.0.0

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 (136) hide show
  1. package/README.md +116 -269
  2. package/dist/autopage-odPz7zZO.js +536 -0
  3. package/dist/autopage-odPz7zZO.js.map +1 -0
  4. package/dist/binary-string-CKVAYI3M.js +24 -0
  5. package/dist/binary-string-CKVAYI3M.js.map +1 -0
  6. package/dist/body-insets-Dw_BeWD_.js +54 -0
  7. package/dist/body-insets-Dw_BeWD_.js.map +1 -0
  8. package/dist/browser.d.ts +29 -9
  9. package/dist/browser.d.ts.map +1 -1
  10. package/dist/browser.js +41 -14
  11. package/dist/browser.js.map +1 -1
  12. package/dist/clip-Bl01BPcN.d.ts +67 -0
  13. package/dist/clip-Bl01BPcN.d.ts.map +1 -0
  14. package/dist/diagnostics-D8ot4Ei7.d.ts +244 -0
  15. package/dist/diagnostics-D8ot4Ei7.d.ts.map +1 -0
  16. package/dist/embedded-fonts-DarT9aoa.d.ts +20 -0
  17. package/dist/embedded-fonts-DarT9aoa.d.ts.map +1 -0
  18. package/dist/entry-compose-DCnvBZz2.d.ts +1046 -0
  19. package/dist/entry-compose-DCnvBZz2.d.ts.map +1 -0
  20. package/dist/{enums-CvRYniUA.d.ts → enums-BUKTUB6V.d.ts} +21 -13
  21. package/dist/{enums-CvRYniUA.d.ts.map → enums-BUKTUB6V.d.ts.map} +1 -1
  22. package/dist/{errors-Bvln0H-7.js → errors-C4oENPcu.js} +92 -2
  23. package/dist/errors-C4oENPcu.js.map +1 -0
  24. package/dist/families.d.ts +260 -0
  25. package/dist/families.d.ts.map +1 -0
  26. package/dist/families.js +57 -0
  27. package/dist/families.js.map +1 -0
  28. package/dist/{fit-BKs0zxMI.js → fit-Cb7naFj6.js} +249 -167
  29. package/dist/fit-Cb7naFj6.js.map +1 -0
  30. package/dist/font-metrics-v5fn7s7e.d.ts +613 -0
  31. package/dist/font-metrics-v5fn7s7e.d.ts.map +1 -0
  32. package/dist/grid-DikTjFey.js +187 -0
  33. package/dist/grid-DikTjFey.js.map +1 -0
  34. package/dist/{html-dom-B0I0QSbU.js → html-dom-Iuog2wdK.js} +121 -91
  35. package/dist/html-dom-Iuog2wdK.js.map +1 -0
  36. package/dist/html.d.ts +6 -6
  37. package/dist/html.d.ts.map +1 -1
  38. package/dist/html.js +7 -6
  39. package/dist/html.js.map +1 -1
  40. package/dist/image-size-CvN2iCA4.js +1611 -0
  41. package/dist/image-size-CvN2iCA4.js.map +1 -0
  42. package/dist/index.d.ts +24 -10
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +31 -11
  45. package/dist/index.js.map +1 -1
  46. package/dist/inspect.d.ts +40 -31
  47. package/dist/inspect.d.ts.map +1 -1
  48. package/dist/inspect.js +40 -48
  49. package/dist/inspect.js.map +1 -1
  50. package/dist/math.d.ts +7 -5
  51. package/dist/math.d.ts.map +1 -1
  52. package/dist/math.js +16 -7
  53. package/dist/math.js.map +1 -1
  54. package/dist/measure.d.ts +12 -225
  55. package/dist/measure.d.ts.map +1 -1
  56. package/dist/measure.js +3 -3
  57. package/dist/node.d.ts +22 -8
  58. package/dist/node.d.ts.map +1 -1
  59. package/dist/node.js +27 -7
  60. package/dist/node.js.map +1 -1
  61. package/dist/notes-Dh12JAbn.js +3264 -0
  62. package/dist/notes-Dh12JAbn.js.map +1 -0
  63. package/dist/options-internal-WqgMf720.js +43 -0
  64. package/dist/options-internal-WqgMf720.js.map +1 -0
  65. package/dist/{package-CaOLXSNi.d.ts → package-J49Ck6S2.d.ts} +27 -12
  66. package/dist/package-J49Ck6S2.d.ts.map +1 -0
  67. package/dist/playbtn-CUqQdoDf.js +22 -0
  68. package/dist/playbtn-CUqQdoDf.js.map +1 -0
  69. package/dist/{slide-ZqAdVvHV.d.ts → pres-C6qgOFAa.d.ts} +1021 -1423
  70. package/dist/pres-C6qgOFAa.d.ts.map +1 -0
  71. package/dist/{presentation-DrJtj3-C.js → presentation-DGYlAWhl.js} +3208 -2727
  72. package/dist/presentation-DGYlAWhl.js.map +1 -0
  73. package/dist/{presentation-types-CDjScsev.d.ts → presentation-types-8jLQHI4M.d.ts} +1070 -683
  74. package/dist/presentation-types-8jLQHI4M.d.ts.map +1 -0
  75. package/dist/read.d.ts +9 -9
  76. package/dist/read.d.ts.map +1 -1
  77. package/dist/read.js +4 -4
  78. package/dist/script.d.ts +80 -66
  79. package/dist/script.d.ts.map +1 -1
  80. package/dist/script.js +2399 -1139
  81. package/dist/script.js.map +1 -1
  82. package/dist/{shapes-BemroU-z.js → shapes-re0KyQk_.js} +2807 -1609
  83. package/dist/shapes-re0KyQk_.js.map +1 -0
  84. package/dist/slide-Dx2ZeVZ6.d.ts +1256 -0
  85. package/dist/slide-Dx2ZeVZ6.d.ts.map +1 -0
  86. package/dist/slide-size-BalTjFuv.js +88 -0
  87. package/dist/slide-size-BalTjFuv.js.map +1 -0
  88. package/dist/{units-internal-Dg95w_YD.js → table-cell-margins-EVg0EwxT.js} +235 -273
  89. package/dist/table-cell-margins-EVg0EwxT.js.map +1 -0
  90. package/dist/table-dom-BTDP3lEP.js +21 -0
  91. package/dist/table-dom-BTDP3lEP.js.map +1 -0
  92. package/dist/text-KnLOtEEu.js +3980 -0
  93. package/dist/text-KnLOtEEu.js.map +1 -0
  94. package/dist/text-anchor-CrYXAfUu.js +176 -0
  95. package/dist/text-anchor-CrYXAfUu.js.map +1 -0
  96. package/dist/transition-speed-kUEWDWTx.js +14 -0
  97. package/dist/transition-speed-kUEWDWTx.js.map +1 -0
  98. package/dist/units-internal-XJlf-hOl.js +649 -0
  99. package/dist/units-internal-XJlf-hOl.js.map +1 -0
  100. package/dist/zip-C0leZZMj.d.ts +67 -0
  101. package/dist/zip-C0leZZMj.d.ts.map +1 -0
  102. package/dist/zip-CKd8ihcf.js +177 -0
  103. package/dist/zip-CKd8ihcf.js.map +1 -0
  104. package/dist/zip.d.ts +3 -68
  105. package/dist/zip.js +3 -163
  106. package/dist/zoom-cX9sllpH.js +8865 -0
  107. package/dist/zoom-cX9sllpH.js.map +1 -0
  108. package/package.json +106 -19
  109. package/skills/ts-pptx-upstream/SKILL.md +58 -57
  110. package/dist/autopage-DkjYZUFD.js +0 -423
  111. package/dist/autopage-DkjYZUFD.js.map +0 -1
  112. package/dist/diagnostics-DfBdDHre.d.ts +0 -829
  113. package/dist/diagnostics-DfBdDHre.d.ts.map +0 -1
  114. package/dist/errors-Bvln0H-7.js.map +0 -1
  115. package/dist/errors-PflMPWBn.d.ts +0 -182
  116. package/dist/errors-PflMPWBn.d.ts.map +0 -1
  117. package/dist/fit-BKs0zxMI.js.map +0 -1
  118. package/dist/html-dom-B0I0QSbU.js.map +0 -1
  119. package/dist/namespaces-BVnNu7sg.js +0 -666
  120. package/dist/namespaces-BVnNu7sg.js.map +0 -1
  121. package/dist/notes-CJFJaG6M.js +0 -1724
  122. package/dist/notes-CJFJaG6M.js.map +0 -1
  123. package/dist/package-CaOLXSNi.d.ts.map +0 -1
  124. package/dist/pres-BcBR3CSM.d.ts +0 -202
  125. package/dist/pres-BcBR3CSM.d.ts.map +0 -1
  126. package/dist/presentation-DrJtj3-C.js.map +0 -1
  127. package/dist/presentation-types-CDjScsev.d.ts.map +0 -1
  128. package/dist/shapes-BemroU-z.js.map +0 -1
  129. package/dist/slide-ZqAdVvHV.d.ts.map +0 -1
  130. package/dist/text-B8SLEaZx.js +0 -11327
  131. package/dist/text-B8SLEaZx.js.map +0 -1
  132. package/dist/units-1kRzYShk.js +0 -231
  133. package/dist/units-1kRzYShk.js.map +0 -1
  134. package/dist/units-internal-Dg95w_YD.js.map +0 -1
  135. package/dist/zip.d.ts.map +0 -1
  136. package/dist/zip.js.map +0 -1
@@ -0,0 +1,187 @@
1
+ import { l as warn } from "./errors-C4oENPcu.js";
2
+ //#region src/gen/table/spans.ts
3
+ /**
4
+ * The largest `colspan`/`rowspan` this library will honour.
5
+ *
6
+ * Unlike the read side's point-cache ceiling there is no format number to borrow: `a:tc@gridSpan`
7
+ * is a bare `xsd:int`. So this is a sanity bound rather than a schema one, and it is set an order
8
+ * of magnitude past PowerPoint's own maximum table (its Insert Table dialog stops at 75 columns
9
+ * and 75 rows), which is what makes it something no authored table can reach. What it stops is
10
+ * the other end, where the allocation takes the host process with it.
11
+ */
12
+ const MAX_TABLE_SPAN = 1e3;
13
+ /**
14
+ * Validate one cell's `colspan`/`rowspan`, warning and falling back to `1` when it is not a whole
15
+ * number in `1..MAX_TABLE_SPAN`.
16
+ *
17
+ * `undefined` is the common case and means "no span" — it warns about nothing and returns `1`.
18
+ * Everything else is caller error: `NaN`, a negative, a fraction and a span past the ceiling all
19
+ * describe a table that cannot be built (a fractional span silently truncates, a negative one
20
+ * shifts every column after it, an enormous one is the allocation above).
21
+ *
22
+ * The parameter is typed `unknown` because this is also **the** reading of a span for the six
23
+ * sites that consume one after {@link withCheckedSpans} has run. Those had six different
24
+ * coercions — `Number(x) ? … : 1`, `Math.max(1, Number(x) || 1)`, `x ?? 1` — which agreed only
25
+ * on the values that were already valid, and one of them let a non-numeric span reach a grid
26
+ * column count as `NaN`. Reading a span through one function is what stops them drifting apart
27
+ * again if the up-front check is ever moved.
28
+ * @param value - the raw option value, as the caller wrote it
29
+ * @param kind - `'colspan'` or `'rowspan'`, for the diagnostic
30
+ * @returns the span to use, at least 1
31
+ */
32
+ function resolveSpan(value, kind) {
33
+ if (value === void 0 || value === null || value === "") return 1;
34
+ if (typeof value !== "number") {
35
+ warn("table/span-out-of-range", `table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`);
36
+ return 1;
37
+ }
38
+ if (!Number.isInteger(value) || value < 1 || value > 1e3) {
39
+ warn("table/span-out-of-range", `table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`);
40
+ return 1;
41
+ }
42
+ return value;
43
+ }
44
+ /**
45
+ * Re-clone `rows` with every out-of-range `colspan`/`rowspan` corrected to `1`.
46
+ *
47
+ * Runs once, up front, so the column count, the `_hmerge`/`_vmerge` dummies, the auto-pager's
48
+ * grid and the emitted `gridSpan`/`rowSpan` attributes all read the same number — checking at
49
+ * each of those sites instead would warn several times per bad cell and could still disagree.
50
+ *
51
+ * A cell whose spans are fine is passed through by identity, not copied: `_spanOrigin` links the
52
+ * merge dummies back to the origin *object*, and the all-valid path is every real table, which
53
+ * must stay allocation-free and byte-identical.
54
+ * @param rows - the rows to check; row arrays are never mutated
55
+ * @returns the same rows with only the offending cells replaced
56
+ */
57
+ function withCheckedSpans(rows) {
58
+ return rows.map((cells) => cells.map((cell) => {
59
+ const opts = cell?.options;
60
+ if (!opts) return cell;
61
+ const colspan = resolveSpan(opts.colspan, "colspan");
62
+ const rowspan = resolveSpan(opts.rowspan, "rowspan");
63
+ const colspanOk = opts.colspan === void 0 || opts.colspan === colspan;
64
+ const rowspanOk = opts.rowspan === void 0 || opts.rowspan === rowspan;
65
+ if (colspanOk && rowspanOk) return cell;
66
+ return {
67
+ ...cell,
68
+ options: {
69
+ ...opts,
70
+ ...opts.colspan === void 0 ? {} : { colspan },
71
+ ...opts.rowspan === void 0 ? {} : { rowspan }
72
+ }
73
+ };
74
+ }));
75
+ }
76
+ /**
77
+ * Whether any cell in the grid carries a hyperlink — on the cell itself, or on any run of a
78
+ * cell whose `text` is a run array.
79
+ *
80
+ * `addTable` uses this to decide whether to stand its black text default down: the default is
81
+ * direct formatting on the table, so it would paint the words *after* a link black rather than
82
+ * letting them follow the link colour. The test used to be
83
+ * `JSON.stringify({ arrRows }).includes('hyperlink')`, which matched the literal word anywhere
84
+ * in the grid's *content* — a cell reading "see the hyperlink docs" suppressed the default for
85
+ * the whole table — and serialized every cell on every `addTable` to ask.
86
+ * @param rows - the table's rows
87
+ */
88
+ function tableHasHyperlink(rows) {
89
+ return rows.some((cells) => cells.some((cell) => {
90
+ if (!cell) return false;
91
+ if (cell.options?.hyperlink) return true;
92
+ if (!Array.isArray(cell.text)) return false;
93
+ return cell.text.some((run) => !!run?.options?.hyperlink);
94
+ }));
95
+ }
96
+ //#endregion
97
+ //#region src/gen/table/grid.ts
98
+ /**
99
+ * How many grid columns a table has: the sum of the first row's colspans.
100
+ *
101
+ * The count cannot come from `rows[0].length` -- a colspan makes one cell occupy several
102
+ * columns -- and it is read off the first row alone, which is the writer's standing rule: a
103
+ * later row wider than the first is ragged input, and the grid it is measured, paged and
104
+ * emitted against is the one `a:tblGrid` declares.
105
+ */
106
+ function tableColCount(rows) {
107
+ const first = rows[0];
108
+ return first ? first.reduce((n, c) => n + resolveSpan(c?.options?.colspan, "colspan"), 0) : 0;
109
+ }
110
+ /**
111
+ * The rowspan-occupancy rule, stated once.
112
+ *
113
+ * A row states only the cells it *starts*: a column held by a `rowspan` from above is filled
114
+ * without the row mentioning it, so a cell's position in its row array is not its column. Tracking
115
+ * that is three operations -- skip what is held, mark what this cell holds, age the holds by a row
116
+ * -- and getting the ageing off by one silently shifts every column below.
117
+ *
118
+ * It has two callers asking different questions on different input. {@link walkTableGrid} places
119
+ * authored `TableCell`s into a grid whose width `a:tblGrid` already declares; `measureGridColumns`
120
+ * (`gen/table/html-dom.ts`) measures how wide an imported HTML table's grid *is*, reading spans off
121
+ * HTML attributes, with no width known up front. Neither can be expressed as the other without
122
+ * giving one of them a mode it does not want -- but the rule underneath is the same rule, and it is
123
+ * here rather than in both.
124
+ *
125
+ * The array is sparse and unbounded on purpose: a caller that knows its width clamps what it
126
+ * `hold`s, and then nothing past that width is ever held, so an unbounded `nextFree` returns the
127
+ * same answer a bounded one would.
128
+ */
129
+ function createRowSpanOccupancy() {
130
+ const held = [];
131
+ return {
132
+ nextFree(col) {
133
+ let free = col;
134
+ while ((held[free] ?? 0) > 0) free++;
135
+ return free;
136
+ },
137
+ hold(col, colSpan, rowSpan) {
138
+ for (let idx = 0; idx < colSpan; idx++) held[col + idx] = rowSpan;
139
+ },
140
+ endRow() {
141
+ for (let idx = 0; idx < held.length; idx++) {
142
+ const rows = held[idx] ?? 0;
143
+ if (rows > 0) held[idx] = rows - 1;
144
+ }
145
+ }
146
+ };
147
+ }
148
+ /**
149
+ * Walk a table's cell grid in row-major order, resolving each authored cell to its
150
+ * grid origin (`row`/`col`) and clamped colspan/rowspan. Tracks rowspan occupancy so
151
+ * a cell never lands beneath one spanned from above. This is the single traversal the
152
+ * auto-pager, the measured-fit shrink pass, {@link computeTableLayout} and the table emitter's
153
+ * merge grid all read, so the table that is paged and measured is the table that is written.
154
+ *
155
+ * A cell that starts past the last grid column is not yielded: a row longer than the first is
156
+ * ragged input, and the grid is the one `a:tblGrid` declares.
157
+ */
158
+ function* walkTableGrid(rows, numCols) {
159
+ const occupancy = createRowSpanOccupancy();
160
+ for (let r = 0; r < rows.length; r++) {
161
+ const row = rows[r];
162
+ if (!row) continue;
163
+ let col = 0;
164
+ for (const cell of row) {
165
+ col = occupancy.nextFree(col);
166
+ if (col >= numCols) break;
167
+ const colspan = resolveSpan(cell?.options?.colspan, "colspan");
168
+ const rowspan = Math.min(resolveSpan(cell?.options?.rowspan, "rowspan"), rows.length - r);
169
+ const colStart = col;
170
+ const colEnd = Math.min(colStart + colspan, numCols);
171
+ occupancy.hold(colStart, colEnd - colStart, rowspan);
172
+ col = colEnd;
173
+ yield {
174
+ cell,
175
+ row: r,
176
+ col: colStart,
177
+ rowSpan: rowspan,
178
+ colSpan: colEnd - colStart
179
+ };
180
+ }
181
+ occupancy.endRow();
182
+ }
183
+ }
184
+ //#endregion
185
+ export { resolveSpan as a, MAX_TABLE_SPAN as i, tableColCount as n, tableHasHyperlink as o, walkTableGrid as r, withCheckedSpans as s, createRowSpanOccupancy as t };
186
+
187
+ //# sourceMappingURL=grid-DikTjFey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-DikTjFey.js","names":[],"sources":["../src/gen/table/spans.ts","../src/gen/table/grid.ts"],"sourcesContent":["/**\n * ts-pptx: table `colspan`/`rowspan` range checking.\n *\n * The spans decide two allocations, on two different paths, and both used to trust the caller:\n * the merge grid's `new Array(colspan - 1)` in `gen/slide/objects/table.ts`, and the auto-pager's\n * per-column depth array, sized from a column count that is a sum of colspans\n * (`gen/table/autopage.ts`). `new Array(4294967294).fill(undefined)` is not a slow path — V8\n * aborts on the allocation and there is no exception to catch — so a table built with\n * `autoPage: true` and one without needed the same guard, which is why it lives here rather than\n * in either of them.\n *\n * This is the write side, so the bad number comes from the calling program rather than from a\n * hostile file, which makes it far less serious than the read-side twin in the chart point caches\n * (`read/oxml/point-cache.ts`, the model this copies). It is still the project's stated line: warn\n * on out-of-range input rather than emit a degenerate result.\n */\n\nimport type { TableCellInternal } from '../../types/internal.js'\nimport { warn } from '../../diagnostics.js'\n\n/**\n * The largest `colspan`/`rowspan` this library will honour.\n *\n * Unlike the read side's point-cache ceiling there is no format number to borrow: `a:tc@gridSpan`\n * is a bare `xsd:int`. So this is a sanity bound rather than a schema one, and it is set an order\n * of magnitude past PowerPoint's own maximum table (its Insert Table dialog stops at 75 columns\n * and 75 rows), which is what makes it something no authored table can reach. What it stops is\n * the other end, where the allocation takes the host process with it.\n */\nexport const MAX_TABLE_SPAN = 1000\n\n/**\n * Validate one cell's `colspan`/`rowspan`, warning and falling back to `1` when it is not a whole\n * number in `1..MAX_TABLE_SPAN`.\n *\n * `undefined` is the common case and means \"no span\" — it warns about nothing and returns `1`.\n * Everything else is caller error: `NaN`, a negative, a fraction and a span past the ceiling all\n * describe a table that cannot be built (a fractional span silently truncates, a negative one\n * shifts every column after it, an enormous one is the allocation above).\n *\n * The parameter is typed `unknown` because this is also **the** reading of a span for the six\n * sites that consume one after {@link withCheckedSpans} has run. Those had six different\n * coercions — `Number(x) ? … : 1`, `Math.max(1, Number(x) || 1)`, `x ?? 1` — which agreed only\n * on the values that were already valid, and one of them let a non-numeric span reach a grid\n * column count as `NaN`. Reading a span through one function is what stops them drifting apart\n * again if the up-front check is ever moved.\n * @param value - the raw option value, as the caller wrote it\n * @param kind - `'colspan'` or `'rowspan'`, for the diagnostic\n * @returns the span to use, at least 1\n */\nexport function resolveSpan(value: unknown, kind: 'colspan' | 'rowspan'): number {\n\tif (value === undefined || value === null || value === '') return 1\n\tif (typeof value !== 'number') {\n\t\twarn(\n\t\t\t'table/span-out-of-range',\n\t\t\t`table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`\n\t\t)\n\t\treturn 1\n\t}\n\tif (!Number.isInteger(value) || value < 1 || value > MAX_TABLE_SPAN) {\n\t\twarn(\n\t\t\t'table/span-out-of-range',\n\t\t\t`table cell: ${kind} must be a whole number between 1 and ${MAX_TABLE_SPAN}; got ${String(value)}. Using 1.`\n\t\t)\n\t\treturn 1\n\t}\n\treturn value\n}\n\n/**\n * Re-clone `rows` with every out-of-range `colspan`/`rowspan` corrected to `1`.\n *\n * Runs once, up front, so the column count, the `_hmerge`/`_vmerge` dummies, the auto-pager's\n * grid and the emitted `gridSpan`/`rowSpan` attributes all read the same number — checking at\n * each of those sites instead would warn several times per bad cell and could still disagree.\n *\n * A cell whose spans are fine is passed through by identity, not copied: `_spanOrigin` links the\n * merge dummies back to the origin *object*, and the all-valid path is every real table, which\n * must stay allocation-free and byte-identical.\n * @param rows - the rows to check; row arrays are never mutated\n * @returns the same rows with only the offending cells replaced\n */\nexport function withCheckedSpans(rows: TableCellInternal[][]): TableCellInternal[][] {\n\treturn rows.map((cells) =>\n\t\tcells.map((cell) => {\n\t\t\tconst opts = cell?.options\n\t\t\tif (!opts) return cell\n\t\t\tconst colspan = resolveSpan(opts.colspan, 'colspan')\n\t\t\tconst rowspan = resolveSpan(opts.rowspan, 'rowspan')\n\t\t\tconst colspanOk = opts.colspan === undefined || opts.colspan === colspan\n\t\t\tconst rowspanOk = opts.rowspan === undefined || opts.rowspan === rowspan\n\t\t\tif (colspanOk && rowspanOk) return cell\n\t\t\treturn {\n\t\t\t\t...cell,\n\t\t\t\toptions: {\n\t\t\t\t\t...opts,\n\t\t\t\t\t...(opts.colspan === undefined ? {} : { colspan }),\n\t\t\t\t\t...(opts.rowspan === undefined ? {} : { rowspan }),\n\t\t\t\t},\n\t\t\t}\n\t\t})\n\t)\n}\n\n/**\n * Whether any cell in the grid carries a hyperlink — on the cell itself, or on any run of a\n * cell whose `text` is a run array.\n *\n * `addTable` uses this to decide whether to stand its black text default down: the default is\n * direct formatting on the table, so it would paint the words *after* a link black rather than\n * letting them follow the link colour. The test used to be\n * `JSON.stringify({ arrRows }).includes('hyperlink')`, which matched the literal word anywhere\n * in the grid's *content* — a cell reading \"see the hyperlink docs\" suppressed the default for\n * the whole table — and serialized every cell on every `addTable` to ask.\n * @param rows - the table's rows\n */\nexport function tableHasHyperlink(rows: TableCellInternal[][]): boolean {\n\treturn rows.some((cells) =>\n\t\tcells.some((cell) => {\n\t\t\tif (!cell) return false\n\t\t\tif (cell.options?.hyperlink) return true\n\t\t\tif (!Array.isArray(cell.text)) return false\n\t\t\treturn cell.text.some((run) => !!run?.options?.hyperlink)\n\t\t})\n\t)\n}\n","/**\n * ts-pptx: a table's cell grid.\n *\n * Rows arrive lopsided -- `row1: [A, B, C]`, `row2: [D]` when the first two columns are held by\n * a rowspan from above -- so a cell's position in its row array is not its column. Four places\n * needed to know where a cell actually lands (the auto-pager, twice, in one function; the\n * measured-fit pass; the table emitter) and each walked the grid itself, tracking rowspan\n * occupancy in its own array with its own off-by-one convention.\n *\n * This is that traversal, once. It lives beside {@link resolveSpan} rather than in `measure/`\n * because the grid is a fact about the authored table, not a measurement of it -- the pager and\n * the emitter want it as much as the fitter does, and `measure/table-fit.ts` was already\n * reaching into `gen/table/` for the span reader it is built on.\n */\n\nimport type { TableCellInternal } from '../../types/internal.js'\nimport { resolveSpan } from './spans.js'\n\n/**\n * How many grid columns a table has: the sum of the first row's colspans.\n *\n * The count cannot come from `rows[0].length` -- a colspan makes one cell occupy several\n * columns -- and it is read off the first row alone, which is the writer's standing rule: a\n * later row wider than the first is ragged input, and the grid it is measured, paged and\n * emitted against is the one `a:tblGrid` declares.\n */\nexport function tableColCount(rows: TableCellInternal[][]): number {\n\tconst first = rows[0]\n\treturn first ? first.reduce((n, c) => n + resolveSpan(c?.options?.colspan, 'colspan'), 0) : 0\n}\n\n/** The bookkeeping a row-major grid walk needs to route around rowspans; see {@link createRowSpanOccupancy}. */\ninterface RowSpanOccupancy {\n\t/** The first column at or after `col` that no rowspan from above is holding. */\n\tnextFree: (col: number) => number\n\t/** Record that `colSpan` columns from `col` are held for `rowSpan` rows, this one included. */\n\thold: (col: number, colSpan: number, rowSpan: number) => void\n\t/** Close the current row: every held column has one fewer row left to hold. */\n\tendRow: () => void\n}\n\n/**\n * The rowspan-occupancy rule, stated once.\n *\n * A row states only the cells it *starts*: a column held by a `rowspan` from above is filled\n * without the row mentioning it, so a cell's position in its row array is not its column. Tracking\n * that is three operations -- skip what is held, mark what this cell holds, age the holds by a row\n * -- and getting the ageing off by one silently shifts every column below.\n *\n * It has two callers asking different questions on different input. {@link walkTableGrid} places\n * authored `TableCell`s into a grid whose width `a:tblGrid` already declares; `measureGridColumns`\n * (`gen/table/html-dom.ts`) measures how wide an imported HTML table's grid *is*, reading spans off\n * HTML attributes, with no width known up front. Neither can be expressed as the other without\n * giving one of them a mode it does not want -- but the rule underneath is the same rule, and it is\n * here rather than in both.\n *\n * The array is sparse and unbounded on purpose: a caller that knows its width clamps what it\n * `hold`s, and then nothing past that width is ever held, so an unbounded `nextFree` returns the\n * same answer a bounded one would.\n */\nexport function createRowSpanOccupancy(): RowSpanOccupancy {\n\t// held[c] = rows still covered by a rowspan started at or above the current row.\n\tconst held: number[] = []\n\treturn {\n\t\tnextFree(col) {\n\t\t\tlet free = col\n\t\t\twhile ((held[free] ?? 0) > 0) free++\n\t\t\treturn free\n\t\t},\n\t\thold(col, colSpan, rowSpan) {\n\t\t\tfor (let idx = 0; idx < colSpan; idx++) held[col + idx] = rowSpan\n\t\t},\n\t\tendRow() {\n\t\t\tfor (let idx = 0; idx < held.length; idx++) {\n\t\t\t\tconst rows = held[idx] ?? 0\n\t\t\t\tif (rows > 0) held[idx] = rows - 1\n\t\t\t}\n\t\t},\n\t}\n}\n\n/** A placed (non-merged origin) cell yielded by {@link walkTableGrid}. */\nexport interface GridPlacement {\n\tcell: TableCellInternal\n\t/** Zero-based grid row of the cell's top-left origin. */\n\trow: number\n\t/** Zero-based grid column of the cell's top-left origin. */\n\tcol: number\n\t/** Rows spanned, clamped to the available rows. */\n\trowSpan: number\n\t/** Columns spanned, clamped to the grid width. */\n\tcolSpan: number\n}\n\n/**\n * Walk a table's cell grid in row-major order, resolving each authored cell to its\n * grid origin (`row`/`col`) and clamped colspan/rowspan. Tracks rowspan occupancy so\n * a cell never lands beneath one spanned from above. This is the single traversal the\n * auto-pager, the measured-fit shrink pass, {@link computeTableLayout} and the table emitter's\n * merge grid all read, so the table that is paged and measured is the table that is written.\n *\n * A cell that starts past the last grid column is not yielded: a row longer than the first is\n * ragged input, and the grid is the one `a:tblGrid` declares.\n */\nexport function* walkTableGrid(rows: TableCellInternal[][], numCols: number): Generator<GridPlacement> {\n\tconst occupancy = createRowSpanOccupancy()\n\tfor (let r = 0; r < rows.length; r++) {\n\t\tconst row = rows[r]\n\t\tif (!row) continue\n\t\tlet col = 0\n\t\tfor (const cell of row) {\n\t\t\tcol = occupancy.nextFree(col)\n\t\t\tif (col >= numCols) break\n\t\t\tconst colspan = resolveSpan(cell?.options?.colspan, 'colspan')\n\t\t\tconst rowspan = Math.min(resolveSpan(cell?.options?.rowspan, 'rowspan'), rows.length - r)\n\t\t\tconst colStart = col\n\t\t\t// Clamped to the declared width, which is also what keeps `nextFree` unbounded and still\n\t\t\t// correct: nothing past `numCols` is ever held, so it never has a reason to walk past it.\n\t\t\tconst colEnd = Math.min(colStart + colspan, numCols)\n\t\t\toccupancy.hold(colStart, colEnd - colStart, rowspan)\n\t\t\tcol = colEnd\n\t\t\tyield { cell, row: r, col: colStart, rowSpan: rowspan, colSpan: colEnd - colStart }\n\t\t}\n\t\toccupancy.endRow()\n\t}\n}\n"],"mappings":";;;;;;;;;;;AA6BA,MAAa,iBAAiB;;;;;;;;;;;;;;;;;;;;AAqB9B,SAAgB,YAAY,OAAgB,MAAqC;CAChF,IAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU,IAAI,OAAO;CAClE,IAAI,OAAO,UAAU,UAAU;EAC9B,KACC,2BACA,eAAe,KAAK,wCAAwC,eAAe,QAAQ,OAAO,KAAK,EAAE,WAClG;EACA,OAAO;CACR;CACA,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAA,KAAwB;EACpE,KACC,2BACA,eAAe,KAAK,wCAAwC,eAAe,QAAQ,OAAO,KAAK,EAAE,WAClG;EACA,OAAO;CACR;CACA,OAAO;AACR;;;;;;;;;;;;;;AAeA,SAAgB,iBAAiB,MAAoD;CACpF,OAAO,KAAK,KAAK,UAChB,MAAM,KAAK,SAAS;EACnB,MAAM,OAAO,MAAM;EACnB,IAAI,CAAC,MAAM,OAAO;EAClB,MAAM,UAAU,YAAY,KAAK,SAAS,SAAS;EACnD,MAAM,UAAU,YAAY,KAAK,SAAS,SAAS;EACnD,MAAM,YAAY,KAAK,YAAY,KAAA,KAAa,KAAK,YAAY;EACjE,MAAM,YAAY,KAAK,YAAY,KAAA,KAAa,KAAK,YAAY;EACjE,IAAI,aAAa,WAAW,OAAO;EACnC,OAAO;GACN,GAAG;GACH,SAAS;IACR,GAAG;IACH,GAAI,KAAK,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ;IAChD,GAAI,KAAK,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ;GACjD;EACD;CACD,CAAC,CACF;AACD;;;;;;;;;;;;;AAcA,SAAgB,kBAAkB,MAAsC;CACvE,OAAO,KAAK,MAAM,UACjB,MAAM,MAAM,SAAS;EACpB,IAAI,CAAC,MAAM,OAAO;EAClB,IAAI,KAAK,SAAS,WAAW,OAAO;EACpC,IAAI,CAAC,MAAM,QAAQ,KAAK,IAAI,GAAG,OAAO;EACtC,OAAO,KAAK,KAAK,MAAM,QAAQ,CAAC,CAAC,KAAK,SAAS,SAAS;CACzD,CAAC,CACF;AACD;;;;;;;;;;;ACnGA,SAAgB,cAAc,MAAqC;CAClE,MAAM,QAAQ,KAAK;CACnB,OAAO,QAAQ,MAAM,QAAQ,GAAG,MAAM,IAAI,YAAY,GAAG,SAAS,SAAS,SAAS,GAAG,CAAC,IAAI;AAC7F;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,yBAA2C;CAE1D,MAAM,OAAiB,CAAC;CACxB,OAAO;EACN,SAAS,KAAK;GACb,IAAI,OAAO;GACX,QAAQ,KAAK,SAAS,KAAK,GAAG;GAC9B,OAAO;EACR;EACA,KAAK,KAAK,SAAS,SAAS;GAC3B,KAAK,IAAI,MAAM,GAAG,MAAM,SAAS,OAAO,KAAK,MAAM,OAAO;EAC3D;EACA,SAAS;GACR,KAAK,IAAI,MAAM,GAAG,MAAM,KAAK,QAAQ,OAAO;IAC3C,MAAM,OAAO,KAAK,QAAQ;IAC1B,IAAI,OAAO,GAAG,KAAK,OAAO,OAAO;GAClC;EACD;CACD;AACD;;;;;;;;;;;AAyBA,UAAiB,cAAc,MAA6B,SAA2C;CACtG,MAAM,YAAY,uBAAuB;CACzC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACrC,MAAM,MAAM,KAAK;EACjB,IAAI,CAAC,KAAK;EACV,IAAI,MAAM;EACV,KAAK,MAAM,QAAQ,KAAK;GACvB,MAAM,UAAU,SAAS,GAAG;GAC5B,IAAI,OAAO,SAAS;GACpB,MAAM,UAAU,YAAY,MAAM,SAAS,SAAS,SAAS;GAC7D,MAAM,UAAU,KAAK,IAAI,YAAY,MAAM,SAAS,SAAS,SAAS,GAAG,KAAK,SAAS,CAAC;GACxF,MAAM,WAAW;GAGjB,MAAM,SAAS,KAAK,IAAI,WAAW,SAAS,OAAO;GACnD,UAAU,KAAK,UAAU,SAAS,UAAU,OAAO;GACnD,MAAM;GACN,MAAM;IAAE;IAAM,KAAK;IAAG,KAAK;IAAU,SAAS;IAAS,SAAS,SAAS;GAAS;EACnF;EACA,UAAU,OAAO;CAClB;AACD"}
@@ -1,9 +1,28 @@
1
- import { r as EMU_PER_INCH, x as warn } from "./units-1kRzYShk.js";
2
- import { n as InvalidOptionError } from "./errors-Bvln0H-7.js";
3
- import { a as inch2Emu } from "./units-internal-Dg95w_YD.js";
4
- import { t as getSlidesForTableRows } from "./autopage-DkjYZUFD.js";
1
+ import { l as warn, n as InvalidOptionError } from "./errors-C4oENPcu.js";
2
+ import { C as usableTableWidthEmu, c as inch2Emu, s as getSmartParseNumber, y as resolveSlideMarginsInches } from "./units-internal-XJlf-hOl.js";
3
+ import { F as EMU_PER_INCH } from "./table-cell-margins-EVg0EwxT.js";
4
+ import { a as resolveSpan, t as createRowSpanOccupancy } from "./grid-DikTjFey.js";
5
+ import { t as getSlidesForTableRows } from "./autopage-odPz7zZO.js";
5
6
  //#region src/gen/table/html-dom.ts
6
7
  /**
8
+ * CSS `text-align` / `vertical-align` values this converter can express as a table cell's own
9
+ * alignment. The two logical values map onto the physical pair; everything else — `justify`,
10
+ * `initial`, a value the browser did not resolve — is absent here and so leaves the cell's
11
+ * alignment alone.
12
+ */
13
+ const CSS_TEXT_ALIGN = {
14
+ left: "left",
15
+ center: "center",
16
+ right: "right",
17
+ start: "left",
18
+ end: "right"
19
+ };
20
+ const CSS_VERTICAL_ALIGN = {
21
+ top: "top",
22
+ middle: "middle",
23
+ bottom: "bottom"
24
+ };
25
+ /**
7
26
  * Stand-in for `getComputedStyle` on a document that has no view — a document produced by
8
27
  * parsing rather than by a browsing context has a `null` `defaultView` and therefore no
9
28
  * cascade to compute against. Every property reads as `''`, which every consumer below
@@ -82,18 +101,25 @@ function rgbToHex(r, g, b) {
82
101
  * Convert a computed CSS border (width string + color string) from `getComputedStyle` into a
83
102
  * pptx `BorderProps`.
84
103
  *
104
+ * `StrokeProps.width` is in **points**, so the px magnitude is converted through
105
+ * {@link htmlCssPxToPoints} rather than copied across: a `1px` CSS border is 0.75pt, not 1pt.
106
+ * This was the third read in this file to make that mistake and the last one left — the font
107
+ * size and the cell padding were each corrected against `DEFAULT_PX_PER_INCH` on their own, and
108
+ * routing this one through the same converter is what stops a fourth from drifting apart again.
109
+ *
85
110
  * Preserves *fractional* widths: a hairline CSS border such as `0.5px` must not be rounded to
86
111
  * `0pt` and silently vanish — the table serializer (`ptsToEmuLenient`) emits fractional points just
87
112
  * fine, so there is no reason to integer-round here. A
88
113
  * computed width of `0` (or a non-finite value) yields `{ type: 'none' }` so we never emit a
89
- * zero-width line.
114
+ * zero-width line. `''`, `auto` and `3em` are non-finite for the same reason
115
+ * {@link parseCssPx} says they are, and take the same exit.
90
116
  * @param {string} widthStr - computed `border-<side>-width`, e.g. `"0.5px"`
91
117
  * @param {string} colorStr - computed `border-<side>-color`, e.g. `"rgb(102, 102, 102)"`
92
118
  * @returns {BorderProps} border props for the cell side
93
119
  */
94
120
  function htmlBorderToProps(widthStr, colorStr) {
95
- const pt = Number(String(widthStr).replace("px", ""));
96
- if (!isFinite(pt) || pt <= 0) return { type: "none" };
121
+ const pt = htmlCssPxToPoints(widthStr);
122
+ if (!Number.isFinite(pt) || pt <= 0) return { type: "none" };
97
123
  return {
98
124
  width: pt,
99
125
  color: cssColorToHex(colorStr) ?? "000000"
@@ -124,7 +150,7 @@ function cssColorToHex(value) {
124
150
  const parts = (rgbMatch[1] ?? "").split(/[,/\s]+/).filter((part) => part.length > 0);
125
151
  if (parts.length < 3) return void 0;
126
152
  const channels = parts.slice(0, 3).map((part) => Number(part.replace("%", "")));
127
- if (channels.some((channel) => !isFinite(channel))) return void 0;
153
+ if (channels.some((channel) => !Number.isFinite(channel))) return void 0;
128
154
  if (parts.length > 3 && Number(parts[3]) === 0) return void 0;
129
155
  const [r = 0, g = 0, b = 0] = channels.map((channel) => Math.max(0, Math.min(255, Math.round(channel))));
130
156
  return rgbToHex(r, g, b);
@@ -150,9 +176,9 @@ function cssColorToHex(value) {
150
176
  * @returns {number} resolved column width
151
177
  */
152
178
  function resolveHtmlColWidth(calcWidth, setWidth, minWidth) {
153
- const safeCalc = isFinite(calcWidth) ? calcWidth : 0;
154
- if (isFinite(setWidth) && setWidth > 0) return setWidth;
155
- return isFinite(minWidth) && minWidth > safeCalc ? minWidth : safeCalc;
179
+ const safeCalc = Number.isFinite(calcWidth) ? calcWidth : 0;
180
+ if (Number.isFinite(setWidth) && setWidth > 0) return setWidth;
181
+ return Number.isFinite(minWidth) && minWidth > safeCalc ? minWidth : safeCalc;
156
182
  }
157
183
  /** A CSS value that is a bare number, or a number with a `px`/`%` unit. Nothing else parses. */
158
184
  const CSS_LENGTH = /^\s*(-?(?:\d+\.?\d*|\.\d+))\s*(px|%)?\s*$/i;
@@ -174,6 +200,30 @@ function parseCssPx(value) {
174
200
  return Number(match[1]);
175
201
  }
176
202
  /**
203
+ * A computed CSS px length as the points every `pt`-measured table property is in, or `NaN` when
204
+ * the value is not an absolute px length.
205
+ *
206
+ * This is the file's **one** px→pt conversion, and it is one because the same mistake was made
207
+ * three separate times under the same stale "px to pt 1:1" note. A default `16px` cell emitted
208
+ * `sz="1600"` — 16pt, a third larger than the 12pt the browser rendered; the cell padding read
209
+ * a px magnitude as the inches `TableCellProps.margin` wants, until 2026-07-31; and a `1px`
210
+ * border was emitted as 1pt, a third too thick. Each was found and corrected on its own, and
211
+ * the next went on being wrong, because there was no shared converter for a sweep to land on.
212
+ * Now there is, for the two properties measured in points. The padding is not one of them --
213
+ * it resolves to inches -- so it divides by `DEFAULT_PX_PER_INCH` at its own site and this
214
+ * comment is the link between them.
215
+ *
216
+ * CSS defines the reference pixel as 1/96in, so the conversion is the same density the `"<n>px"`
217
+ * coordinate unit uses. An `em`, a `%` or a keyword has no absolute size here and comes back
218
+ * `NaN`, which each caller reads as its own kind of absence — the font size is left off the
219
+ * cell, and a border becomes `{ type: 'none' }`.
220
+ * @param value - computed CSS value, e.g. `"16px"`
221
+ * @returns the length in points, or `NaN` when the value is not an absolute px length
222
+ */
223
+ function htmlCssPxToPoints(value) {
224
+ return parseCssPx(value) * 72 / 96;
225
+ }
226
+ /**
177
227
  * Parse a whole row of computed CSS widths into a column basis, or reject the set.
178
228
  *
179
229
  * The result is only ever used *proportionally* (each column's share of the total), so the
@@ -197,7 +247,7 @@ function parseCssWidthBasis(values) {
197
247
  const match = CSS_LENGTH.exec(String(value ?? ""));
198
248
  if (!match) return [];
199
249
  const magnitude = Number(match[1]);
200
- if (!isFinite(magnitude) || magnitude < 0) return [];
250
+ if (!Number.isFinite(magnitude) || magnitude < 0) return [];
201
251
  const valueUnit = (match[2] ?? "px").toLowerCase();
202
252
  if (!unit) unit = valueUnit;
203
253
  else if (unit !== valueUnit) return [];
@@ -238,7 +288,7 @@ function parseCssWidthBasis(values) {
238
288
  * @returns {number[]} the basis vector to run the proportional calc on
239
289
  */
240
290
  function pickColWidthBasis(measured, cssWidths) {
241
- const sum = (arr) => arr.reduce((acc, n) => acc + (isFinite(n) ? n : 0), 0);
291
+ const sum = (arr) => arr.reduce((acc, n) => acc + (Number.isFinite(n) ? n : 0), 0);
242
292
  if (sum(measured) > 0) return [...measured];
243
293
  if (cssWidths.length === measured.length && sum(cssWidths) > 0) return [...cssWidths];
244
294
  return measured.map(() => 1);
@@ -253,9 +303,10 @@ function pickColWidthBasis(measured, cssWidths) {
253
303
  * @param {unknown} value - the raw attribute value
254
304
  * @returns {number} tracks covered, at least 1
255
305
  */
256
- function gridSpan(value) {
306
+ function gridSpan(value, kind) {
257
307
  const num = Math.floor(Number(value));
258
- return isFinite(num) && num > 1 ? num : 1;
308
+ if (!Number.isFinite(num) || num <= 1) return 1;
309
+ return num > 1e3 ? resolveSpan(num, kind) : num;
259
310
  }
260
311
  /**
261
312
  * Measure the column grid a set of table rows actually occupies.
@@ -271,27 +322,26 @@ function gridSpan(value) {
271
322
  * the two is exactly the padding a ragged row needs; the merge cells for `colspan`/`rowspan` are
272
323
  * *not* padding — the table emitter synthesizes those itself, so they are counted as filled here.
273
324
  *
274
- * Spans are read through {@link gridSpan}, so a bad attribute cannot shift the whole grid.
325
+ * Spans are read through {@link gridSpan}, so a bad attribute cannot shift the whole grid. The
326
+ * occupancy bookkeeping underneath is {@link createRowSpanOccupancy}, shared with
327
+ * `walkTableGrid` -- the same rowspan rule, asked a different question: that one places authored
328
+ * cells into a grid whose width is already declared, this one measures how wide the grid *is*.
275
329
  * @param {readonly (readonly GridCellSpans[])[]} rows - per-row cell spans, in emission order
276
330
  * @returns {{ columns: number, filled: number[] }} grid width, and columns reached per row
277
331
  */
278
332
  function measureGridColumns(rows) {
279
- const carry = [];
333
+ const occupancy = createRowSpanOccupancy();
280
334
  const filled = [];
281
335
  for (const row of rows) {
282
336
  let col = 0;
283
337
  for (const cell of row) {
284
- while ((carry[col] ?? 0) > 0) col++;
285
- const colspan = gridSpan(cell?.colspan);
286
- for (let idx = 0; idx < colspan; idx++) carry[col + idx] = gridSpan(cell?.rowspan);
338
+ col = occupancy.nextFree(col);
339
+ const colspan = gridSpan(cell?.colspan, "colspan");
340
+ occupancy.hold(col, colspan, gridSpan(cell?.rowspan, "rowspan"));
287
341
  col += colspan;
288
342
  }
289
- while ((carry[col] ?? 0) > 0) col++;
290
- filled.push(col);
291
- for (let idx = 0; idx < carry.length; idx++) {
292
- const held = carry[idx] ?? 0;
293
- if (held > 0) carry[idx] = held - 1;
294
- }
343
+ filled.push(occupancy.nextFree(col));
344
+ occupancy.endRow();
295
345
  }
296
346
  return {
297
347
  columns: filled.reduce((max, reached) => reached > max ? reached : max, 0),
@@ -312,7 +362,7 @@ function measureGridColumns(rows) {
312
362
  */
313
363
  function extendColBasis(basis, columns) {
314
364
  const extended = [...basis];
315
- const total = extended.reduce((acc, width) => acc + (isFinite(width) ? width : 0), 0);
365
+ const total = extended.reduce((acc, width) => acc + (Number.isFinite(width) ? width : 0), 0);
316
366
  const share = extended.length > 0 && total > 0 ? total / extended.length : 1;
317
367
  while (extended.length < columns) extended.push(share);
318
368
  return extended;
@@ -463,10 +513,8 @@ function collectTableRows(table) {
463
513
  * @param {TableToSlidesProps} options - array of options (e.g.: tabsize)
464
514
  */
465
515
  function genTableToSlides(pptx, target, options = {}) {
466
- const opts = options || {};
516
+ const opts = { ...options };
467
517
  const masterSlide = resolveMasterSlide(pptx, opts.masterTitle);
468
- opts.slideMargin = opts.slideMargin || opts.slideMargin === 0 ? opts.slideMargin : .5;
469
- let emuSlideTabW = opts.w || pptx.presLayout.width;
470
518
  const arrObjTabHeadRows = [];
471
519
  const arrObjTabBodyRows = [];
472
520
  const arrObjTabFootRows = [];
@@ -481,25 +529,9 @@ function genTableToSlides(pptx, target, options = {}) {
481
529
  ];
482
530
  let intTabW = 0;
483
531
  const ctx = resolveDomContext(target, opts);
484
- if (masterSlide?._margin) {
485
- if (Array.isArray(masterSlide._margin)) arrInchMargins = masterSlide._margin;
486
- else if (!isNaN(masterSlide._margin)) arrInchMargins = [
487
- masterSlide._margin,
488
- masterSlide._margin,
489
- masterSlide._margin,
490
- masterSlide._margin
491
- ];
492
- opts.slideMargin = arrInchMargins;
493
- } else if (opts?.slideMargin) {
494
- if (Array.isArray(opts.slideMargin)) arrInchMargins = opts.slideMargin;
495
- else if (!isNaN(opts.slideMargin)) arrInchMargins = [
496
- opts.slideMargin,
497
- opts.slideMargin,
498
- opts.slideMargin,
499
- opts.slideMargin
500
- ];
501
- }
502
- emuSlideTabW = (opts.w ? inch2Emu(opts.w) : pptx.presLayout.width) - inch2Emu(arrInchMargins[1] + arrInchMargins[3]);
532
+ arrInchMargins = resolveSlideMarginsInches(masterSlide?._margin, opts.slideMargin);
533
+ const tableXEmu = opts.x === void 0 || opts.x === null ? inch2Emu(arrInchMargins[3]) : getSmartParseNumber(opts.x, "X", pptx.presLayout);
534
+ const emuSlideTabW = opts.w === void 0 || opts.w === null ? usableTableWidthEmu(pptx.presLayout, tableXEmu, arrInchMargins) : getSmartParseNumber(opts.w, "X", pptx.presLayout);
503
535
  if (opts.verbose) {
504
536
  console.log("[[VERBOSE MODE]]");
505
537
  console.log("|-- `tableToSlides` ----------------------------------------------------|");
@@ -510,19 +542,28 @@ function genTableToSlides(pptx, target, options = {}) {
510
542
  console.log(`| emuSlideTabW .................................... = ${(emuSlideTabW / EMU_PER_INCH).toFixed(1)}`);
511
543
  }
512
544
  const domRows = collectTableRows(ctx.table);
513
- const { columns: intColCnt, filled: arrRowFilled } = measureGridColumns(domRows.map(({ row }) => rowCells(row).map((cell) => ({
514
- colspan: Number(cell.getAttribute("colspan")),
515
- rowspan: Number(cell.getAttribute("rowspan"))
516
- }))));
545
+ const spansByCell = /* @__PURE__ */ new Map();
546
+ const spansOf = (cell) => {
547
+ let spans = spansByCell.get(cell);
548
+ if (!spans) {
549
+ spans = {
550
+ colspan: gridSpan(cell.getAttribute("colspan"), "colspan"),
551
+ rowspan: gridSpan(cell.getAttribute("rowspan"), "rowspan")
552
+ };
553
+ spansByCell.set(cell, spans);
554
+ }
555
+ return spans;
556
+ };
557
+ const { columns: intColCnt, filled: arrRowFilled } = measureGridColumns(domRows.map(({ row }) => rowCells(row).map(spansOf)));
517
558
  const srcRow = domRows.find(({ row }) => rowCells(row).length > 0);
518
559
  if (!srcRow) throw new InvalidOptionError("html/table-has-no-cells", "tableToSlides: the table has no cells to convert - expected at least one <tr> with a <td>/<th>.");
519
560
  const arrColSrc = [];
520
561
  const arrCellSpans = [];
521
562
  rowCells(srcRow.row).forEach((cell) => {
522
563
  const offsetW = Number(cell.offsetWidth);
523
- const measured = isFinite(offsetW) ? offsetW : 0;
564
+ const measured = Number.isFinite(offsetW) ? offsetW : 0;
524
565
  arrTabColCssW.push(ctx.getComputedStyle(cell).getPropertyValue("width"));
525
- const span = gridSpan(cell.getAttribute("colspan"));
566
+ const span = spansOf(cell).colspan;
526
567
  arrCellSpans.push(span);
527
568
  for (let idxc = 0; idxc < span; idxc++) {
528
569
  arrTabColW.push(Math.round(measured / span));
@@ -559,33 +600,19 @@ function genTableToSlides(pptx, target, options = {}) {
559
600
  const cellOpts = {
560
601
  bold: !!(style.getPropertyValue("font-weight") === "bold" || Number(style.getPropertyValue("font-weight")) >= 500),
561
602
  color: textColor,
562
- fill: { color: fillColor },
563
- fontSize: Number(style.getPropertyValue("font-size").replace(/[a-z]/gi, ""))
603
+ fill: { color: fillColor }
564
604
  };
605
+ const fontSizePt = htmlCssPxToPoints(style.getPropertyValue("font-size"));
606
+ if (Number.isFinite(fontSizePt)) cellOpts.fontSize = fontSizePt;
565
607
  const fontFace = ((style.getPropertyValue("font-family") || "").split(",")[0] ?? "").replace(/"/g, "").replace("inherit", "").replace("initial", "");
566
- const colspan = gridSpan(cell.getAttribute("colspan"));
567
- const rowspan = gridSpan(cell.getAttribute("rowspan"));
608
+ const { colspan, rowspan } = spansOf(cell);
568
609
  if (fontFace) cellOpts.fontFace = fontFace;
569
610
  if (colspan > 1) cellOpts.colspan = colspan;
570
611
  if (rowspan > 1) cellOpts.rowspan = rowspan;
571
- if ([
572
- "left",
573
- "center",
574
- "right",
575
- "start",
576
- "end"
577
- ].includes(style.getPropertyValue("text-align"))) {
578
- const align = style.getPropertyValue("text-align").replace("start", "left").replace("end", "right");
579
- cellOpts.align = align === "center" ? "center" : align === "left" ? "left" : align === "right" ? "right" : void 0;
580
- }
581
- if ([
582
- "top",
583
- "middle",
584
- "bottom"
585
- ].includes(style.getPropertyValue("vertical-align"))) {
586
- const valign = style.getPropertyValue("vertical-align");
587
- cellOpts.valign = valign === "top" ? "top" : valign === "middle" ? "middle" : valign === "bottom" ? "bottom" : void 0;
588
- }
612
+ const align = CSS_TEXT_ALIGN[style.getPropertyValue("text-align")];
613
+ if (align) cellOpts.align = align;
614
+ const valign = CSS_VERTICAL_ALIGN[style.getPropertyValue("vertical-align")];
615
+ if (valign) cellOpts.valign = valign;
589
616
  if (style.getPropertyValue("padding-left")) {
590
617
  const cellMargin = [
591
618
  0,
@@ -600,7 +627,7 @@ function genTableToSlides(pptx, target, options = {}) {
600
627
  "padding-left"
601
628
  ].forEach((val, idxs) => {
602
629
  const pad = parseCssPx(style.getPropertyValue(val));
603
- cellMargin[idxs] = isFinite(pad) ? pad / 96 : 0;
630
+ cellMargin[idxs] = Number.isFinite(pad) ? pad / 96 : 0;
604
631
  });
605
632
  cellOpts.margin = cellMargin;
606
633
  }
@@ -642,29 +669,32 @@ function genTableToSlides(pptx, target, options = {}) {
642
669
  ...arrObjTabHeadRows,
643
670
  ...arrObjTabBodyRows,
644
671
  ...arrObjTabFootRows
645
- ], opts, pptx.presLayout, masterSlide).forEach((slide, idxTr) => {
646
- const newSlide = pptx.addSlide({ masterTitle: opts.masterTitle || void 0 });
647
- if (idxTr === 0) opts.y = opts.y || arrInchMargins[0];
648
- if (idxTr > 0) opts.y = opts.autoPageSlideStartY || arrInchMargins[0];
672
+ ], opts, pptx.presLayout, masterSlide).forEach((slide) => {
673
+ const newSlide = pptx.addSlide(opts.masterTitle ? { masterTitle: opts.masterTitle } : {});
674
+ if (slide.y !== void 0) opts.y = slide.y;
649
675
  if (opts.verbose) console.log(`| opts.autoPageSlideStartY: ${opts.autoPageSlideStartY} / arrInchMargins[0]: ${arrInchMargins[0]} => opts.y = ${opts.y}`);
650
- newSlide.addTable(slide.rows, {
651
- x: opts.x || arrInchMargins[3],
652
- y: opts.y,
676
+ const slideTableProps = {
677
+ x: opts.x ?? arrInchMargins[3],
653
678
  w: Number(emuSlideTabW) / EMU_PER_INCH,
654
679
  colW: arrColW,
655
680
  autoPage: false
656
- });
681
+ };
682
+ if (opts.y !== void 0) slideTableProps.y = opts.y;
683
+ newSlide.addTable(slide.rows, slideTableProps);
657
684
  if (opts.addImage) {
658
685
  opts.addImage.options = opts.addImage.options || {};
659
686
  if (!opts.addImage.image || !opts.addImage.image.path && !opts.addImage.image.data) warn("html/image-missing-source", "tableToSlides.addImage requires either `path` or `data`");
660
687
  else {
661
688
  const imageProps = opts.addImage.image.path ? { path: opts.addImage.image.path } : { data: opts.addImage.image.data };
689
+ const imageOptions = opts.addImage.options;
690
+ const geometry = {};
691
+ if (imageOptions.x !== void 0) geometry.x = imageOptions.x;
692
+ if (imageOptions.y !== void 0) geometry.y = imageOptions.y;
693
+ if (imageOptions.w !== void 0) geometry.w = imageOptions.w;
694
+ if (imageOptions.h !== void 0) geometry.h = imageOptions.h;
662
695
  newSlide.addImage({
663
696
  ...imageProps,
664
- x: opts.addImage.options.x,
665
- y: opts.addImage.options.y,
666
- w: opts.addImage.options.w,
667
- h: opts.addImage.options.h
697
+ ...geometry
668
698
  });
669
699
  }
670
700
  }
@@ -676,4 +706,4 @@ function genTableToSlides(pptx, target, options = {}) {
676
706
  //#endregion
677
707
  export { genTableToSlides as t };
678
708
 
679
- //# sourceMappingURL=html-dom-B0I0QSbU.js.map
709
+ //# sourceMappingURL=html-dom-Iuog2wdK.js.map