@shbernal/ts-pptx 1.0.0 → 2.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 (53) hide show
  1. package/README.md +3 -1
  2. package/dist/browser.d.ts +5 -5
  3. package/dist/browser.js +2 -2
  4. package/dist/{diagnostics-DzY9Tyfm.d.ts → diagnostics-CQ0JWc9m.d.ts} +4 -21
  5. package/dist/{diagnostics-DzY9Tyfm.d.ts.map → diagnostics-CQ0JWc9m.d.ts.map} +1 -1
  6. package/dist/{errors-DRLpOpgQ.d.ts → errors-B22h8Qd0.d.ts} +3 -3
  7. package/dist/{errors-DRLpOpgQ.d.ts.map → errors-B22h8Qd0.d.ts.map} +1 -1
  8. package/dist/errors-DGE9zh3U.js.map +1 -1
  9. package/dist/{fit-CbxyHN69.js → fit-BSWY0AYt.js} +0 -0
  10. package/dist/{fit-CbxyHN69.js.map → fit-BSWY0AYt.js.map} +1 -1
  11. package/dist/{html-dom-wVa3TiG7.js → html-dom-BQLUntho.js} +2 -2
  12. package/dist/html-dom-BQLUntho.js.map +1 -0
  13. package/dist/html.d.ts +3 -3
  14. package/dist/html.js +1 -1
  15. package/dist/{image-size-C5Z1sKof.js → image-size-C8uYE8GJ.js} +3 -3
  16. package/dist/{image-size-C5Z1sKof.js.map → image-size-C8uYE8GJ.js.map} +1 -1
  17. package/dist/index.d.ts +5 -5
  18. package/dist/index.js +2 -2
  19. package/dist/inspect.d.ts +1 -1
  20. package/dist/inspect.js +2 -2
  21. package/dist/math.d.ts +1 -1
  22. package/dist/math.js +2 -1
  23. package/dist/math.js.map +1 -1
  24. package/dist/measure.d.ts +2 -2
  25. package/dist/measure.js +1 -1
  26. package/dist/node.d.ts +5 -5
  27. package/dist/node.js +1 -1
  28. package/dist/{pres-5x1bjCzk.d.ts → pres-GU-jjBEx.d.ts} +2 -2
  29. package/dist/{pres-5x1bjCzk.d.ts.map → pres-GU-jjBEx.d.ts.map} +1 -1
  30. package/dist/{presentation-RGOiun5P.d.ts → presentation-CVaTZw1V.d.ts} +316 -18
  31. package/dist/presentation-CVaTZw1V.d.ts.map +1 -0
  32. package/dist/{presentation-B0JWdTN1.js → presentation-MJe9WDi4.js} +21 -27
  33. package/dist/presentation-MJe9WDi4.js.map +1 -0
  34. package/dist/read.d.ts +4 -4
  35. package/dist/read.js +2 -2
  36. package/dist/script.d.ts +2 -2
  37. package/dist/script.d.ts.map +1 -1
  38. package/dist/script.js +0 -0
  39. package/dist/script.js.map +1 -1
  40. package/dist/{shapes-BZU8UTW2.js → shapes-CaOgR0i1.js} +910 -22
  41. package/dist/shapes-CaOgR0i1.js.map +1 -0
  42. package/dist/{slide-B6mDaM-P.d.ts → slide-BBlElWr9.d.ts} +223 -92
  43. package/dist/slide-BBlElWr9.d.ts.map +1 -0
  44. package/dist/{text-WRUbOy2r.js → text-B1ZrPEeK.js} +441 -186
  45. package/dist/text-B1ZrPEeK.js.map +1 -0
  46. package/dist/zip.d.ts +1 -1
  47. package/package.json +9 -20
  48. package/dist/html-dom-wVa3TiG7.js.map +0 -1
  49. package/dist/presentation-B0JWdTN1.js.map +0 -1
  50. package/dist/presentation-RGOiun5P.d.ts.map +0 -1
  51. package/dist/shapes-BZU8UTW2.js.map +0 -1
  52. package/dist/slide-B6mDaM-P.d.ts.map +0 -1
  53. package/dist/text-WRUbOy2r.js.map +0 -1
@@ -2,9 +2,9 @@ import { n as warn, r as warnOnce } from "./diagnostics-DYQC7xLV.js";
2
2
  import { n as InvalidOptionError, o as UnsupportedFeatureError, r as MediaError, t as InternalError } from "./errors-DGE9zh3U.js";
3
3
  import { a as FIXED_PCT_PER_PERCENT, d as emuToInches, g as pixelsToEmu, i as EMU_PER_POINT, l as STANDARD_LAYOUTS, m as inchesToEmu, r as EMU_PER_INCH, s as PERCENT_SCALE, t as ANGLE_UNITS_PER_DEGREE, v as ptToHundredths } from "./units-B-JUKwCS.js";
4
4
  import { $ as connectorPresetFor, C as DEF_PRES_LAYOUT_NAME, D as DEF_TEXT_GLOW, E as DEF_SLIDE_MARGIN_IN, F as PIECHART_COLORS, G as PlaceholderType, I as REGEX_HEX_COLOR, K as SchemeColor, L as SLDNUMFLDID, M as LAYOUT_IDX_SERIES_BASE, N as LETTERS, O as DEF_TEXT_SHADOW, Q as asChartType, R as XML_DECL, S as DEF_PRES_LAYOUT, T as DEF_SHAPE_SHADOW, Z as VALID_SHAPE_PRESETS, _ as DEF_CELL_BORDER, a as lineWidthToEmu, b as DEF_CHART_GRIDLINE, c as resolveTableColWidthsEmu, d as AXIS_ID_CATEGORY_PRIMARY, et as isChartExType, f as AXIS_ID_CATEGORY_SECONDARY, g as BARCHART_COLORS, h as AXIS_ID_VALUE_SECONDARY, i as inch2Emu, k as IMG_BROKEN, l as transparencyToAlpha, m as AXIS_ID_VALUE_PRIMARY, n as convertRotationDegrees, o as marginToEmu, p as AXIS_ID_SERIES_PRIMARY, r as getSmartParseNumber, s as opacityToAlpha, t as convertArcAngle, u as valToPts, v as DEF_CELL_MARGIN_IN, x as DEF_FONT_COLOR, y as DEF_CHART_BORDER } from "./units-internal-7JcMfYti.js";
5
- import { a as decodeBase64ToBytes, n as getImageSizeFromBase64, o as svgMarkupToDataUri, t as fitSrcRectPercents } from "./image-size-C5Z1sKof.js";
5
+ import { a as decodeBase64ToBytes, n as getImageSizeFromBase64, o as svgMarkupToDataUri, t as fitSrcRectPercents } from "./image-size-C8uYE8GJ.js";
6
6
  import { t as getSlidesForTableRows } from "./autopage-tmfjRzL4.js";
7
- import { _ as parseFontMetrics, m as FontMetricsRegistry, n as measureText, r as computeTableLayout, t as applyMeasuredFit } from "./fit-CbxyHN69.js";
7
+ import { _ as parseFontMetrics, m as FontMetricsRegistry, n as measureText, r as computeTableLayout, t as applyMeasuredFit } from "./fit-BSWY0AYt.js";
8
8
  import { a as flattenEmbeddedFaces, i as FONT_REL_TYPE, n as FONT_DATA_CONTENT_TYPE, o as serializeEmbeddedFontLst, r as FONT_DATA_EXTENSION, t as EMBEDDED_FONT_SLOTS } from "./embedded-fonts-MaynAHa9.js";
9
9
  import { ZipWriter } from "./zip.js";
10
10
  //#region src/media/content-type.ts
@@ -1829,7 +1829,10 @@ function groupObjectsDefinition(target, objectNames, opts) {
1829
1829
  const key = encodeXmlAttrValue(name);
1830
1830
  const matches = target._slideObjects.filter((obj) => obj.options?.objectName === key);
1831
1831
  const [obj, ambiguous] = matches;
1832
- if (!obj) throw new InvalidOptionError("group/unresolved-object-name", `groupObjects(): cannot group "${name}" — ${findNameInGroups(target._slideObjects, key) ? "it is already inside a group (an object can only belong to one group)" : "no top-level object on this slide has that objectName"}.`);
1832
+ if (!obj) {
1833
+ const hint = findNameInGroups(target._slideObjects, key) ? "it is already inside a group (an object can only belong to one group)" : "no top-level object on this slide has that objectName";
1834
+ throw new InvalidOptionError("group/unresolved-object-name", `groupObjects(): cannot group "${name}" — ${hint}.`);
1835
+ }
1833
1836
  if (ambiguous) throw new InvalidOptionError("group/ambiguous-object-name", `groupObjects(): objectName "${name}" is ambiguous — ${matches.length} objects on this slide share it. Give them unique objectNames.`);
1834
1837
  if (!GROUPABLE_TYPES.includes(obj._type) || obj.options?.placeholder) {
1835
1838
  const kind = obj.options?.placeholder ? "placeholder" : obj._type;
@@ -2148,6 +2151,44 @@ function normalizeBorderTuple(border) {
2148
2151
  border
2149
2152
  ];
2150
2153
  }
2154
+ /** Fill a border's defaulted keys, preserving anything else the caller set (`cap`, `dashType`, …). */
2155
+ function withBorderDefaults(side) {
2156
+ return {
2157
+ ...side,
2158
+ type: side.type || DEF_CELL_BORDER.type,
2159
+ color: side.color || DEF_CELL_BORDER.color,
2160
+ width: typeof side.width === "number" ? side.width : DEF_CELL_BORDER.width
2161
+ };
2162
+ }
2163
+ /**
2164
+ * Resolve `TableProps.outerBorder` into the `[top, right, bottom, left]` tuple the emitter
2165
+ * applies to the table's edge cells, with `undefined` for a side the caller left out.
2166
+ *
2167
+ * A sparse side is *not* the same as `{ type: 'none' }`: it means "leave this edge to
2168
+ * whatever `border` (or the cell's own `options.border`) already drew", whereas `'none'` is
2169
+ * an explicit instruction to erase the rule there. Keeping the hole is what lets
2170
+ * `outerBorder: [rule, undefined, rule, undefined]` add rules above and below a table
2171
+ * without also clearing its left and right edges.
2172
+ */
2173
+ function normalizeOuterBorder(outer) {
2174
+ if (!outer || typeof outer !== "object") return void 0;
2175
+ const sides = Array.isArray(outer) ? outer : [
2176
+ outer,
2177
+ outer,
2178
+ outer,
2179
+ outer
2180
+ ];
2181
+ const resolved = [
2182
+ 0,
2183
+ 1,
2184
+ 2,
2185
+ 3
2186
+ ].map((idx) => {
2187
+ const side = sides[idx];
2188
+ return side && typeof side === "object" ? withBorderDefaults(side) : void 0;
2189
+ });
2190
+ return resolved.some((side) => side !== void 0) ? resolved : void 0;
2191
+ }
2151
2192
  /**
2152
2193
  * Adds a table object to a slide definition.
2153
2194
  * @param {PresSlideInternal} target - slide object that the table should be added to
@@ -2197,6 +2238,9 @@ function applyTableHeaderColumnSugar(tableRows, opt) {
2197
2238
  /**
2198
2239
  * Transform loosely-typed table rows (strings / numbers / TableCell) into a grid of
2199
2240
  * well-formed TableCell objects with fully-resolved 4-side cell borders.
2241
+ *
2242
+ * @param srcRows - the rows as authored, after the `headerRow`/`columns` sugar
2243
+ * @param opt - the table's options
2200
2244
  */
2201
2245
  function normalizeTableRows(srcRows, opt) {
2202
2246
  const arrRows = [];
@@ -2238,12 +2282,7 @@ function normalizeTableRows(srcRows, opt) {
2238
2282
  3
2239
2283
  ].forEach((idx) => {
2240
2284
  const side = cellBorderTuple[idx];
2241
- cellBorderTuple[idx] = {
2242
- ...side,
2243
- type: side.type || DEF_CELL_BORDER.type,
2244
- color: side.color || DEF_CELL_BORDER.color,
2245
- width: typeof side.width === "number" ? side.width : DEF_CELL_BORDER.width
2246
- };
2285
+ cellBorderTuple[idx] = withBorderDefaults(side);
2247
2286
  });
2248
2287
  newCellOptions.border = cellBorderTuple;
2249
2288
  newRow.push(newCell);
@@ -2259,10 +2298,11 @@ function normalizeTableRows(srcRows, opt) {
2259
2298
  * the fill. Tables were the last major object kind not wired into `registerImageFillMedia`
2260
2299
  * (shapes do it at `define/shape.ts`, text boxes at `define/text.ts`).
2261
2300
  *
2262
- * Two fill sources are walked, which between them cover all four ways a fill reaches a cell:
2301
+ * Three fill sources are walked, which between them cover every way a picture reaches a table:
2263
2302
  * the resolved cells (per-cell `options.fill`, plus `headerRow` and `columns[i]`, both baked
2264
- * onto cells by the sugar step above), and the table-level `fill`, which is *not* baked —
2265
- * `gen/slide/objects/table.ts` copies it onto each cell at emit time.
2303
+ * onto cells by the sugar step above), the table-level `fill`, which is *not* baked —
2304
+ * `gen/slide/objects/table.ts` copies it onto each cell at emit time — and `tableFill`, which
2305
+ * lands on `a:tblPr` itself and so needs its own relationship for the same reason.
2266
2306
  *
2267
2307
  * Keyed on fill **object identity**, not on the image source. The sugar spreads its options
2268
2308
  * shallowly, so one `headerRow` fill object is shared by every cell it styles; registering
@@ -2285,6 +2325,7 @@ function registerTableImageFills(target, rows, opt) {
2285
2325
  registerImageFillMedia(target, fill);
2286
2326
  };
2287
2327
  register(opt.fill);
2328
+ register(opt.tableFill);
2288
2329
  rows.forEach((row) => {
2289
2330
  row.forEach((cell) => {
2290
2331
  register(cell.options?.fill);
@@ -2319,7 +2360,7 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
2319
2360
  ];
2320
2361
  if (!Array.isArray(opt.margin) || opt.margin.length !== 4 || opt.margin.some((v) => typeof v !== "number" || !Number.isFinite(v))) opt.margin = DEF_CELL_MARGIN_IN;
2321
2362
  if (!JSON.stringify({ arrRows }).includes("hyperlink")) {
2322
- if (!opt.color) opt.color = opt.color || "000000";
2363
+ if (!opt.color) opt.color = DEF_FONT_COLOR;
2323
2364
  }
2324
2365
  if (typeof opt.border === "string") {
2325
2366
  warn("table/invalid-border", "addTable `border` option must be an object. Ex: `{border: {type:'none'}}`");
@@ -2332,14 +2373,15 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
2332
2373
  2,
2333
2374
  3
2334
2375
  ].forEach((idx) => {
2335
- border[idx] = border[idx] ? {
2336
- ...border[idx],
2337
- type: border[idx].type || DEF_CELL_BORDER.type,
2338
- color: border[idx].color || DEF_CELL_BORDER.color,
2339
- width: border[idx].width || DEF_CELL_BORDER.width
2340
- } : { type: "none" };
2376
+ const side = border[idx];
2377
+ border[idx] = side ? withBorderDefaults(side) : { type: "none" };
2341
2378
  });
2342
2379
  }
2380
+ if (typeof opt.outerBorder === "string") {
2381
+ warn("table/invalid-outer-border", "addTable `outerBorder` option must be an object. Ex: `{outerBorder: {type:'solid'}}`");
2382
+ opt.outerBorder = void 0;
2383
+ }
2384
+ opt.outerBorder = normalizeOuterBorder(opt.outerBorder);
2343
2385
  opt.autoPage = typeof opt.autoPage === "boolean" ? opt.autoPage : false;
2344
2386
  opt.autoPagePlaceholder = typeof opt.autoPagePlaceholder === "boolean" ? opt.autoPagePlaceholder : false;
2345
2387
  opt.autoPageRepeatHeader = typeof opt.autoPageRepeatHeader === "boolean" ? opt.autoPageRepeatHeader : false;
@@ -2381,7 +2423,7 @@ function addTableDefinition(target, tableRows, options, slideLayout, presLayout,
2381
2423
  }
2382
2424
  } else if (opt.w) {} else opt.w = Math.floor((presLayout._sizeW || presLayout.width) / EMU_PER_INCH - arrTableMargin[1] - arrTableMargin[3]);
2383
2425
  if (opt.fitColumns === "shrink") {
2384
- const availWin = (presLayout._sizeW || presLayout.width) / EMU_PER_INCH - getSmartParseNumber(opt.x, "X", presLayout) / EMU_PER_INCH - arrTableMargin[3];
2426
+ const availWin = (presLayout._sizeW || presLayout.width) / EMU_PER_INCH - getSmartParseNumber(opt.x, "X", presLayout) / EMU_PER_INCH - arrTableMargin[1];
2385
2427
  if (availWin > 0) {
2386
2428
  if (Array.isArray(opt.colW)) {
2387
2429
  const sumIn = opt.colW.reduce((p, n) => p + (Number.isFinite(n) ? n : 0), 0);
@@ -3045,23 +3087,99 @@ function genXmlColorSelection(props) {
3045
3087
  case "image":
3046
3088
  outText += genXmlImageFill(typeof props === "string" ? void 0 : props);
3047
3089
  break;
3048
- default:
3049
- outText += "";
3050
- break;
3090
+ default: outText += "";
3051
3091
  }
3052
3092
  }
3053
3093
  return outText;
3054
3094
  }
3055
3095
  //#endregion
3056
3096
  //#region src/gen/drawingml/line.ts
3097
+ /** Every key `BorderProps` defines. Keep in step with the interface in `types/style.ts`. */
3098
+ const BORDER_KEYS = [
3099
+ "type",
3100
+ "dashType",
3101
+ "color",
3102
+ "width",
3103
+ "transparency",
3104
+ "cap"
3105
+ ];
3106
+ /**
3107
+ * The `ST_PresetLineDashVal` tokens `BorderProps.dashType` accepts — the same set
3108
+ * `ShapeLineProps.dashType` does, so a caller who knows one knows the other.
3109
+ */
3110
+ const BORDER_DASH_VALUES = [
3111
+ "solid",
3112
+ "dot",
3113
+ "dash",
3114
+ "lgDash",
3115
+ "dashDot",
3116
+ "lgDashDot",
3117
+ "lgDashDotDot",
3118
+ "sysDash",
3119
+ "sysDot",
3120
+ "sysDashDot",
3121
+ "sysDashDotDot"
3122
+ ];
3123
+ /**
3124
+ * Resolve the `a:prstDash/@val` a border should emit.
3125
+ *
3126
+ * `BorderProps.type` is a three-way switch, so on its own it can only say "dashed" and
3127
+ * every dashed border collapses onto `sysDash`. `dashType` names the preset directly and
3128
+ * therefore wins when both are given; `type: 'none'` never reaches here, being decided by
3129
+ * the caller before any dash is chosen.
3130
+ *
3131
+ * A value outside `ST_PresetLineDashVal` would make the part schema-invalid, which
3132
+ * PowerPoint reports as a corrupt file rather than a mis-set option — so an unrecognized
3133
+ * one is reported and dropped back to what `type` implies.
3134
+ * @param {BorderProps} border - the caller's border properties
3135
+ * @returns {string} a value legal for `a:prstDash/@val`
3136
+ */
3137
+ function resolveBorderDash(border) {
3138
+ const fromType = border.type === "dash" ? "sysDash" : "solid";
3139
+ const dash = border.dashType;
3140
+ if (dash === void 0 || dash === null) return fromType;
3141
+ if (BORDER_DASH_VALUES.includes(dash)) return dash;
3142
+ warnOnce("border/invalid-dash-type", `border: dashType \`${String(dash)}\` is not a valid value and is ignored — use one of ${BORDER_DASH_VALUES.join(", ")}.`, {
3143
+ received: dash,
3144
+ valid: BORDER_DASH_VALUES
3145
+ });
3146
+ return fromType;
3147
+ }
3148
+ /**
3149
+ * Report an authored key that is not part of `BorderProps`, which the library would
3150
+ * otherwise drop without a sound.
3151
+ *
3152
+ * TypeScript's excess-property check already rejects a stray key on a border written
3153
+ * *inline* at the call site. It deliberately does not fire when the border is built as
3154
+ * a variable first (`const b = {...}; addTable(rows, { border: b })`) — a variable may
3155
+ * legitimately be a supertype. That exemption covers precisely the reuse pattern a
3156
+ * shared grid style encourages, so the mistake reaches here typed as valid and the
3157
+ * wrong-named value is discarded during generation. A `.pptx` gives no other signal:
3158
+ * nothing throws, the deck opens, and the border simply renders at its default weight.
3159
+ * @param border - the caller's border properties
3160
+ */
3161
+ function warnUnknownBorderKeys(border) {
3162
+ for (const key in border) {
3163
+ if (!Object.hasOwn(border, key) || BORDER_KEYS.includes(key)) continue;
3164
+ warnOnce("border/unknown-key", `border: unknown option \`${key}\` is ignored — valid keys are ${BORDER_KEYS.join(", ")}. Line thickness is \`width\`, in points.`, {
3165
+ received: key,
3166
+ valid: BORDER_KEYS
3167
+ });
3168
+ }
3169
+ }
3057
3170
  /**
3058
3171
  * Resolve a border's line width in points, falling back to `defaultPt` when `width`
3059
3172
  * is not a usable number.
3173
+ *
3174
+ * Every `BorderProps` the library reads — table cell borders, table-style regions, and
3175
+ * every chart border — resolves its width through here, so this doubles as the one
3176
+ * place that can vet a border's shape for all of them ({@link warnUnknownBorderKeys}).
3060
3177
  * @param {BorderProps} border - border properties (may carry `width`)
3061
3178
  * @param {number} defaultPt - width to use when `width` is not a finite number
3062
3179
  * @returns {number} resolved width in points
3063
3180
  */
3064
3181
  function resolveBorderWidth(border, defaultPt) {
3182
+ warnUnknownBorderKeys(border);
3065
3183
  const val = border.width;
3066
3184
  return typeof val === "number" && !isNaN(val) ? val : defaultPt;
3067
3185
  }
@@ -6352,9 +6470,7 @@ function genXmlParagraphProperties(textObj, isDefault) {
6352
6470
  case "justify":
6353
6471
  paragraphPropXml += " algn=\"just\"";
6354
6472
  break;
6355
- default:
6356
- paragraphPropXml += "";
6357
- break;
6473
+ default: paragraphPropXml += "";
6358
6474
  }
6359
6475
  if (opts.lineSpacing) strXmlLnSpc = el("a:lnSpc", null, raw(voidEl("a:spcPts", { val: clampLineSpacingPts(opts.lineSpacing) })));
6360
6476
  else if (opts.lineSpacingMultiple) strXmlLnSpc = el("a:lnSpc", null, raw(voidEl("a:spcPct", { val: Math.round(opts.lineSpacingMultiple * PERCENT_SCALE) })));
@@ -7094,10 +7210,7 @@ function genXmlCustGeom(options, cx, cy, layout) {
7094
7210
  pt(point.x, point.y)
7095
7211
  ].map(raw), BEZ_INDENT));
7096
7212
  break;
7097
- case "quadratic":
7098
- nodes.push(el("a:quadBezTo", null, [pt(point.curve.x1, point.curve.y1), pt(point.x, point.y)].map(raw), BEZ_INDENT));
7099
- break;
7100
- default: break;
7213
+ case "quadratic": nodes.push(el("a:quadBezTo", null, [pt(point.curve.x1, point.curve.y1), pt(point.x, point.y)].map(raw), BEZ_INDENT));
7101
7214
  }
7102
7215
  else if ("close" in point) nodes.push(voidEl("a:close", null, SPACE_BEFORE_SLASH));
7103
7216
  else if (point.moveTo || i === 0) nodes.push(el("a:moveTo", null, raw(pt(point.x, point.y))));
@@ -7214,12 +7327,15 @@ const ImageSizingXml = {
7214
7327
  const r = imgSize.w - (boxDim.x + boxDim.w);
7215
7328
  const t = boxDim.y;
7216
7329
  const b = imgSize.h - (boxDim.y + boxDim.h);
7217
- if (l < 0 || r < 0 || t < 0 || b < 0) throw new InvalidOptionError("image/crop-window-overflows", `addImage sizing.type 'crop': crop window overflows image bounds — ${[
7218
- l < 0 && `x (${l < 0 ? -l : 0} past left edge)`,
7219
- r < 0 && `x+w (${-r} past right edge)`,
7220
- t < 0 && `y (${-t} past top edge)`,
7221
- b < 0 && `y+h (${-b} past bottom edge)`
7222
- ].filter(Boolean).join(", ")}. Ensure x≥0, y≥0, x+w≤w, y+h≤h.`);
7330
+ if (l < 0 || r < 0 || t < 0 || b < 0) {
7331
+ const over = [
7332
+ l < 0 && `x (${l < 0 ? -l : 0} past left edge)`,
7333
+ r < 0 && `x+w (${-r} past right edge)`,
7334
+ t < 0 && `y (${-t} past top edge)`,
7335
+ b < 0 && `y+h (${-b} past bottom edge)`
7336
+ ].filter(Boolean).join(", ");
7337
+ throw new InvalidOptionError("image/crop-window-overflows", `addImage sizing.type 'crop': crop window overflows image bounds — ${over}. Ensure x≥0, y≥0, x+w≤w, y+h≤h.`);
7338
+ }
7223
7339
  return voidEl("a:srcRect", {
7224
7340
  l: Math.round(1e5 * (l / imgSize.w)),
7225
7341
  r: Math.round(1e5 * (r / imgSize.w)),
@@ -7483,13 +7599,64 @@ function renderOleObject(slideItemObj, idx, x, y, cx, cy) {
7483
7599
  //#endregion
7484
7600
  //#region src/gen/drawingml/table-border.ts
7485
7601
  /**
7486
- * Emit the `<a:lnL>/<a:lnR>/<a:lnT>/<a:lnB>` border children of an `<a:tcPr>` for a table cell.
7487
- * Shared by normal cells and the dummy span (`_hmerge`/`_vmerge`) cells so a merged region's
7488
- * outer edges render with the same border as its origin cell.
7489
- * @param {BorderProps[]} cellBorder - 4-tuple of border props in [top, right, bottom, left] order
7490
- * @return {string} concatenated border element XML, in the LRTB document order PowerPoint expects
7602
+ * One `<a:lnX>` border element. Every side of a table cell — the four edges and the two
7603
+ * diagonals — is a `CT_LineProperties`, so they differ only in element name.
7604
+ * @param {string} name - the element's local name (`lnL`, `lnTlToBr`, …)
7605
+ * @param {BorderProps} border - the resolved border for that side
7606
+ * @return {string} the border element XML
7607
+ */
7608
+ function genBorderLine(name, border) {
7609
+ const cap = createLineCap(border.cap);
7610
+ if (border.type === "none") return el(`a:${name}`, {
7611
+ w: 0,
7612
+ cap,
7613
+ cmpd: "sng",
7614
+ algn: "ctr"
7615
+ }, raw(voidEl("a:noFill")));
7616
+ return el(`a:${name}`, {
7617
+ w: valToPts(resolveBorderWidth(border, 1)),
7618
+ cap,
7619
+ cmpd: "sng",
7620
+ algn: "ctr"
7621
+ }, [
7622
+ genXmlColorSelection({
7623
+ color: border.color ?? "363636",
7624
+ transparency: border.transparency
7625
+ }),
7626
+ voidEl("a:prstDash", { val: resolveBorderDash(border) }),
7627
+ voidEl("a:round"),
7628
+ voidEl("a:headEnd", {
7629
+ type: "none",
7630
+ w: "med",
7631
+ len: "med"
7632
+ }),
7633
+ voidEl("a:tailEnd", {
7634
+ type: "none",
7635
+ w: "med",
7636
+ len: "med"
7637
+ })
7638
+ ].map(raw));
7639
+ }
7640
+ /**
7641
+ * Emit the border children of an `<a:tcPr>` for a table cell: the four edges, then the two
7642
+ * diagonals when the cell asks for them.
7643
+ *
7644
+ * The edges are shared by normal cells and the dummy span (`_hmerge`/`_vmerge`) cells so a
7645
+ * merged region's outer edges render with the same border as its origin cell. The diagonals
7646
+ * are **not**: a diagonal across a merged region is one stroke corner-to-corner, and
7647
+ * repeating it on each covered cell would draw a sawtooth instead. Only the span origin
7648
+ * carries them, which is also where PowerPoint puts them.
7649
+ *
7650
+ * A side may be missing, and missing is not the same as `{type:'none'}`: `none` writes an
7651
+ * explicit `w="0"` rule, which is direct formatting and overrides whatever a built-in table
7652
+ * style would have drawn there, while an omitted side leaves that edge to the style. The
7653
+ * definition step sends every cell here dense; a caller reaching this directly may not.
7654
+ *
7655
+ * @param {BorderProps[]} cellBorder - up to a 4-tuple of border props in [top, right, bottom, left] order
7656
+ * @param {TableCellDiagonals} [diagonal] - the cell's optional corner-to-corner rules
7657
+ * @return {string} concatenated border element XML, in the document order PowerPoint expects
7491
7658
  */
7492
- function genTableCellBorderXml(cellBorder) {
7659
+ function genTableCellBorderXml(cellBorder, diagonal) {
7493
7660
  let strXml = "";
7494
7661
  [
7495
7662
  {
@@ -7511,41 +7678,205 @@ function genTableCellBorderXml(cellBorder) {
7511
7678
  ].forEach((obj) => {
7512
7679
  const border = cellBorder[obj.idx];
7513
7680
  if (!border) return;
7514
- const cap = createLineCap(border.cap);
7515
- if (border.type !== "none") strXml += el(`a:${obj.name}`, {
7516
- w: valToPts(resolveBorderWidth(border, 1)),
7517
- cap,
7518
- cmpd: "sng",
7519
- algn: "ctr"
7520
- }, [
7521
- genXmlColorSelection({
7522
- color: border.color ?? "363636",
7523
- transparency: border.transparency
7524
- }),
7525
- voidEl("a:prstDash", { val: border.type === "dash" ? "sysDash" : "solid" }),
7526
- voidEl("a:round"),
7527
- voidEl("a:headEnd", {
7528
- type: "none",
7529
- w: "med",
7530
- len: "med"
7531
- }),
7532
- voidEl("a:tailEnd", {
7533
- type: "none",
7534
- w: "med",
7535
- len: "med"
7536
- })
7537
- ].map(raw));
7538
- else strXml += el(`a:${obj.name}`, {
7539
- w: 0,
7540
- cap,
7541
- cmpd: "sng",
7542
- algn: "ctr"
7543
- }, raw(voidEl("a:noFill")));
7681
+ strXml += genBorderLine(obj.name, border);
7544
7682
  });
7683
+ if (diagonal?.tlToBr) strXml += genBorderLine("lnTlToBr", diagonal.tlToBr);
7684
+ if (diagonal?.blToTr) strXml += genBorderLine("lnBlToTr", diagonal.blToTr);
7545
7685
  return strXml;
7546
7686
  }
7547
7687
  //#endregion
7688
+ //#region src/gen/drawingml/table-cell3d.ts
7689
+ /** `ST_BevelPresetType`. */
7690
+ const BEVEL_PRESETS = [
7691
+ "relaxedInset",
7692
+ "circle",
7693
+ "slope",
7694
+ "cross",
7695
+ "angle",
7696
+ "softRound",
7697
+ "convex",
7698
+ "coolSlant",
7699
+ "divot",
7700
+ "riblet",
7701
+ "hardEdge",
7702
+ "artDeco"
7703
+ ];
7704
+ /** `ST_PresetMaterialType`. */
7705
+ const MATERIALS = [
7706
+ "legacyMatte",
7707
+ "legacyPlastic",
7708
+ "legacyMetal",
7709
+ "legacyWireframe",
7710
+ "matte",
7711
+ "plastic",
7712
+ "metal",
7713
+ "warmMatte",
7714
+ "translucentPowder",
7715
+ "powder",
7716
+ "dkEdge",
7717
+ "softEdge",
7718
+ "clear",
7719
+ "flat",
7720
+ "softmetal"
7721
+ ];
7722
+ /** `ST_LightRigType`. */
7723
+ const LIGHT_RIGS = [
7724
+ "legacyFlat1",
7725
+ "legacyFlat2",
7726
+ "legacyFlat3",
7727
+ "legacyFlat4",
7728
+ "legacyNormal1",
7729
+ "legacyNormal2",
7730
+ "legacyNormal3",
7731
+ "legacyNormal4",
7732
+ "legacyHarsh1",
7733
+ "legacyHarsh2",
7734
+ "legacyHarsh3",
7735
+ "legacyHarsh4",
7736
+ "threePt",
7737
+ "balanced",
7738
+ "soft",
7739
+ "harsh",
7740
+ "flood",
7741
+ "contrasting",
7742
+ "morning",
7743
+ "sunrise",
7744
+ "sunset",
7745
+ "chilly",
7746
+ "freezing",
7747
+ "flat",
7748
+ "twoPt",
7749
+ "glow",
7750
+ "brightRoom"
7751
+ ];
7752
+ /** `ST_LightRigDirection`. */
7753
+ const LIGHT_DIRECTIONS = [
7754
+ "tl",
7755
+ "t",
7756
+ "tr",
7757
+ "l",
7758
+ "r",
7759
+ "bl",
7760
+ "b",
7761
+ "br"
7762
+ ];
7763
+ /**
7764
+ * Vet one enumerated value before it reaches the XML. Anything outside its `ST_` union would
7765
+ * make the slide part schema-invalid, and PowerPoint reports that as a corrupt file rather
7766
+ * than as a mis-set option — so an unrecognized value is reported and the attribute dropped,
7767
+ * leaving the renderer on the schema default.
7768
+ */
7769
+ function resolveEnum(value, valid, field) {
7770
+ if (value === void 0 || value === null) return null;
7771
+ if (valid.includes(value)) return value;
7772
+ warnOnce("table/invalid-cell3d", `table cell: cell3D \`${field}\` value \`${String(value)}\` is not valid and is ignored — use one of ${valid.join(", ")}.`, {
7773
+ received: value,
7774
+ field,
7775
+ valid
7776
+ });
7777
+ return null;
7778
+ }
7779
+ /**
7780
+ * A bevel dimension in EMU (`ST_PositiveCoordinate`), from a width in points.
7781
+ * A negative or non-finite value cannot be written, so it falls back to the attribute's
7782
+ * own default of 76200 EMU (6pt) rather than emitting something PowerPoint would reject.
7783
+ */
7784
+ function bevelSizeEmu(points, field) {
7785
+ if (points === void 0 || points === null) return null;
7786
+ if (!Number.isFinite(points) || points < 0) {
7787
+ warnOnce("table/invalid-cell3d", `table cell: cell3D \`${field}\` must be a non-negative number of points; \`${String(points)}\` is ignored.`, {
7788
+ received: points,
7789
+ field
7790
+ });
7791
+ return null;
7792
+ }
7793
+ return valToPts(points);
7794
+ }
7795
+ /**
7796
+ * Emit a cell's `<a:cell3D>`, or `''` when it has none.
7797
+ * @param {TableCell3DProps} [cell3D] - the cell's 3-D options
7798
+ * @return {string} the `a:cell3D` element XML
7799
+ */
7800
+ function genTableCell3DXml(cell3D) {
7801
+ if (!cell3D || typeof cell3D !== "object") return "";
7802
+ const bevel = voidEl("a:bevel", {
7803
+ w: bevelSizeEmu(cell3D.width, "width"),
7804
+ h: bevelSizeEmu(cell3D.height, "height"),
7805
+ prst: resolveEnum(cell3D.preset, BEVEL_PRESETS, "preset")
7806
+ });
7807
+ const rig = resolveEnum(cell3D.lightRig?.rig, LIGHT_RIGS, "lightRig.rig");
7808
+ const dir = resolveEnum(cell3D.lightRig?.dir, LIGHT_DIRECTIONS, "lightRig.dir");
7809
+ const lightRig = rig && dir ? voidEl("a:lightRig", {
7810
+ rig,
7811
+ dir
7812
+ }) : "";
7813
+ if (cell3D.lightRig && !lightRig) warnOnce("table/invalid-cell3d", "table cell: cell3D `lightRig` needs both `rig` and `dir` (both are required by CT_LightRig); the light rig is dropped and the bevel takes the renderer default.", { received: cell3D.lightRig });
7814
+ return el("a:cell3D", { prstMaterial: resolveEnum(cell3D.material, MATERIALS, "material") }, [raw(bevel), lightRig ? raw(lightRig) : null]);
7815
+ }
7816
+ //#endregion
7548
7817
  //#region src/gen/slide/objects/table.ts
7818
+ /** The two values `ST_TextHorzOverflowType` allows on `a:tcPr/@horzOverflow`. */
7819
+ const HORZ_OVERFLOW_VALUES = ["clip", "overflow"];
7820
+ /**
7821
+ * Validate a cell's `horzOverflow` before it reaches the XML. Anything outside
7822
+ * `ST_TextHorzOverflowType` would make the slide part schema-invalid — and PowerPoint
7823
+ * reports that as a corrupt file, not as a mis-set option — so an unrecognized value is
7824
+ * reported and dropped instead of written. `undefined` (the common case) emits nothing.
7825
+ */
7826
+ function resolveHorzOverflow(value) {
7827
+ if (value === void 0 || value === null) return null;
7828
+ if (HORZ_OVERFLOW_VALUES.includes(value)) return value;
7829
+ warnOnce("table/invalid-horz-overflow", `table cell: horzOverflow \`${String(value)}\` is not a valid value and is ignored — use ${HORZ_OVERFLOW_VALUES.join(" or ")}.`, {
7830
+ received: value,
7831
+ valid: HORZ_OVERFLOW_VALUES
7832
+ });
7833
+ return null;
7834
+ }
7835
+ /**
7836
+ * Overlay `TableProps.outerBorder` onto one cell's own 4-side border tuple.
7837
+ *
7838
+ * The perimeter is decided per **grid position**, not per authored cell, which is what makes
7839
+ * merges work: a colspan's origin sits at the left of its span and its covered `_hmerge`
7840
+ * cells sit to the right, so a span straddling the last column gets that column's rule on the
7841
+ * covered cell — exactly where PowerPoint defines a merged region's outer edge. A cell in the
7842
+ * table's interior touches no edge and comes back untouched.
7843
+ *
7844
+ * Returns the input array (not a copy) when nothing applies, so the common no-perimeter path
7845
+ * allocates nothing and stays byte-identical. Never mutates: `arrTabRows` holds the caller's
7846
+ * own cell objects and repeated `write()` calls must not accumulate borders.
7847
+ *
7848
+ * @param base - the cell's resolved `[top, right, bottom, left]` borders, or `null` when it has none
7849
+ * @param outer - the normalized perimeter tuple, `undefined` for a side the caller left out
7850
+ * @param at - where this cell sits in the merge grid
7851
+ * @returns the borders to emit, or `null` when there are none and the perimeter adds none
7852
+ */
7853
+ function applyOuterBorder(base, outer, at) {
7854
+ if (!outer) return base;
7855
+ const onEdge = [
7856
+ at.rIdx === 0,
7857
+ at.cIdx === at.lastCol,
7858
+ at.rIdx === at.lastRow,
7859
+ at.cIdx === 0
7860
+ ];
7861
+ const applies = [
7862
+ 0,
7863
+ 1,
7864
+ 2,
7865
+ 3
7866
+ ].filter((idx) => onEdge[idx] && outer[idx]);
7867
+ if (applies.length === 0) return base;
7868
+ const merged = base ? [...base] : [
7869
+ { type: "none" },
7870
+ { type: "none" },
7871
+ { type: "none" },
7872
+ { type: "none" }
7873
+ ];
7874
+ for (const idx of applies) {
7875
+ const side = outer[idx];
7876
+ if (side) merged[idx] = side;
7877
+ }
7878
+ return merged;
7879
+ }
7549
7880
  /**
7550
7881
  * Render a `table` slide object to its `<p:graphicFrame>` XML (merge-grid, row/col spans, per-cell styling).
7551
7882
  */
@@ -7589,8 +7920,15 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
7589
7920
  firstCol: objTabOpts.hasFirstColumn ? "1" : null,
7590
7921
  lastCol: objTabOpts.hasLastColumn ? "1" : null
7591
7922
  };
7592
- tblInner = objTabOpts.tableStyle ? el("a:tblPr", tblPrAttrs, raw(el("a:tableStyleId", null, objTabOpts.tableStyle))) : voidEl("a:tblPr", tblPrAttrs);
7593
- }
7923
+ const tblPrChildren = (objTabOpts.tableFill ? genXmlColorSelection(objTabOpts.tableFill) : "") + (objTabOpts.tableStyle ? el("a:tableStyleId", null, objTabOpts.tableStyle) : "");
7924
+ tblInner = tblPrChildren ? el("a:tblPr", tblPrAttrs, raw(tblPrChildren)) : voidEl("a:tblPr", tblPrAttrs);
7925
+ }
7926
+ const outerBorder = !objTabOpts.outerBorder ? void 0 : Array.isArray(objTabOpts.outerBorder) ? objTabOpts.outerBorder : [
7927
+ objTabOpts.outerBorder,
7928
+ objTabOpts.outerBorder,
7929
+ objTabOpts.outerBorder,
7930
+ objTabOpts.outerBorder
7931
+ ];
7594
7932
  {
7595
7933
  const gridColsEmu = resolveTableColWidthsEmu(objTabOpts.colW, cx, intColCnt);
7596
7934
  tblInner += el("a:tblGrid", null, gridColsEmu.map((w) => raw(voidEl("a:gridCol", { w }))));
@@ -7642,8 +7980,14 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
7642
7980
  else if (objTabOpts.rowH && !isNaN(Number(objTabOpts.rowH))) intRowH = inch2Emu(Number(objTabOpts.rowH));
7643
7981
  else if (itemOpts.cy || itemOpts.h) intRowH = Math.round((itemOpts.h ? cy : typeof itemOpts.cy === "number" ? itemOpts.cy : 1) / arrTabRows.length);
7644
7982
  const rowCells = [];
7645
- cells.forEach((cellObj) => {
7983
+ cells.forEach((cellObj, cIdx) => {
7646
7984
  const cell = cellObj;
7985
+ const at = {
7986
+ rIdx,
7987
+ cIdx,
7988
+ lastRow: arrTabRows.length - 1,
7989
+ lastCol: cells.length - 1
7990
+ };
7647
7991
  const cellSpanAttrs = {
7648
7992
  rowSpan: cell.options?.rowspan && cell.options.rowspan > 1 ? cell.options.rowspan : void 0,
7649
7993
  gridSpan: cell.options?.colspan && cell.options.colspan > 1 ? cell.options.colspan : void 0,
@@ -7652,11 +7996,11 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
7652
7996
  };
7653
7997
  if (cell._hmerge || cell._vmerge) {
7654
7998
  const origin = cell._spanOrigin;
7999
+ const originOpts = origin?.options || {};
7655
8000
  let spanPrXml = "";
8001
+ const originBorder = applyOuterBorder(Array.isArray(originOpts.border) ? originOpts.border : null, outerBorder, at);
8002
+ if (originBorder) spanPrXml += genTableCellBorderXml(originBorder);
7656
8003
  if (origin) {
7657
- const originOpts = origin.options || {};
7658
- const originBorder = Array.isArray(originOpts.border) ? originOpts.border : null;
7659
- if (originBorder) spanPrXml += genTableCellBorderXml(originBorder);
7660
8004
  const spanFill = originOpts.fill || "";
7661
8005
  if (spanFill) spanPrXml += genXmlColorSelection(spanFill);
7662
8006
  }
@@ -7694,16 +8038,25 @@ function renderTableObject(slideItemObj, idx, x, y, cx, cy, placeholderObj, item
7694
8038
  cellMargin
7695
8039
  ];
7696
8040
  if (!Array.isArray(cellMargin) || cellMargin.length !== 4 || cellMargin.some((v) => typeof v !== "number" || !isFinite(v))) cellMargin = DEF_CELL_MARGIN_IN;
8041
+ const cellHorzOverflow = resolveHorzOverflow(cellOpts.horzOverflow);
7697
8042
  const tcPrAttrs = {
7698
8043
  marL: marginToEmu(cellMargin[3]),
7699
8044
  marR: marginToEmu(cellMargin[1]),
7700
8045
  marT: marginToEmu(cellMargin[0]),
7701
8046
  marB: marginToEmu(cellMargin[2]),
7702
8047
  anchor: cellValign,
7703
- vert: cellTextDir
8048
+ anchorCtr: cellOpts.anchorCtr ? "1" : null,
8049
+ vert: cellTextDir,
8050
+ horzOverflow: cellHorzOverflow
7704
8051
  };
7705
- const cellBorder = Array.isArray(cellOpts.border) ? cellOpts.border : null;
7706
- rowCells.push(el("a:tc", cellSpanAttrs, [raw(genXmlTextBody(cell)), raw(el("a:tcPr", tcPrAttrs, [cellBorder ? raw(genTableCellBorderXml(cellBorder)) : null, raw(cellFill)], { closePrefix: " " }))], { closePrefix: " " }));
8052
+ const cellBorder = applyOuterBorder(Array.isArray(cellOpts.border) ? cellOpts.border : null, outerBorder, at);
8053
+ const cellDiagonal = cellOpts.diagonal;
8054
+ const cellBorderXml = cellBorder || cellDiagonal ? genTableCellBorderXml(cellBorder ?? [], cellDiagonal) : "";
8055
+ rowCells.push(el("a:tc", cellSpanAttrs, [raw(genXmlTextBody(cell)), raw(el("a:tcPr", tcPrAttrs, [
8056
+ raw(cellBorderXml),
8057
+ raw(genTableCell3DXml(cellOpts.cell3D)),
8058
+ raw(cellFill)
8059
+ ], { closePrefix: " " }))], { closePrefix: " " }));
7707
8060
  });
7708
8061
  tblInner += el("a:tr", { h: intRowH }, rowCells.map(raw));
7709
8062
  });
@@ -8204,9 +8557,7 @@ function slideObjectToXml(slide) {
8204
8557
  strSlideXml += "</p:grpSp>";
8205
8558
  break;
8206
8559
  }
8207
- default:
8208
- strSlideXml += "";
8209
- break;
8560
+ default: strSlideXml += "";
8210
8561
  }
8211
8562
  return strSlideXml;
8212
8563
  };
@@ -9614,79 +9965,11 @@ function makeXmlViewProps() {
9614
9965
  * @see: http://openxmldeveloper.org/discussions/formats/f/13/p/2398/8107.aspx
9615
9966
  * @return {string} XML
9616
9967
  */
9617
- function makeXmlTableStyles(tableStyles = []) {
9618
- const attrs = {
9968
+ function makeXmlTableStyles() {
9969
+ return XML_DECL + "\r\n" + voidEl("a:tblStyleLst", {
9619
9970
  "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
9620
9971
  def: "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"
9621
- };
9622
- if (!tableStyles || tableStyles.length === 0) return XML_DECL + "\r\n" + voidEl("a:tblStyleLst", attrs);
9623
- return XML_DECL + "\r\n" + el("a:tblStyleLst", attrs, tableStyles.map(({ guid, def }) => raw(el("a:tblStyle", {
9624
- styleId: guid,
9625
- styleName: def.name
9626
- }, [
9627
- ["wholeTbl", def.wholeTbl],
9628
- ["band1H", def.band1H],
9629
- ["band2H", def.band2H],
9630
- ["band1V", def.band1V],
9631
- ["band2V", def.band2V],
9632
- ["lastCol", def.lastCol],
9633
- ["firstCol", def.firstCol],
9634
- ["lastRow", def.lastRow],
9635
- ["firstRow", def.firstRow]
9636
- ].map(([name, region]) => region ? raw(genXmlTableStyleRegion(name, region)) : null)))));
9637
- }
9638
- /**
9639
- * Build one `CT_TablePartStyle` region (e.g. `firstRow`, `band1H`) for a custom table style.
9640
- * Emits `tcTxStyle` (text) before `tcStyle` (cell fill/borders) per the schema sequence.
9641
- * @param {string} name - region element name
9642
- * @param {TableStyleRegionProps} region - region styling
9643
- * @return {string} XML
9644
- */
9645
- function genXmlTableStyleRegion(name, region) {
9646
- const children = [region.bold !== void 0 || region.italic !== void 0 || region.color ? raw(el("a:tcTxStyle", {
9647
- b: region.bold ? "on" : null,
9648
- i: region.italic ? "on" : null
9649
- }, [raw(voidEl("a:fontRef", { idx: "minor" })), region.color ? raw(createColorElement(region.color)) : null])) : null, region.border !== void 0 || region.fill !== void 0 ? raw(el("a:tcStyle", null, [region.border !== void 0 ? raw(genXmlTableStyleBorders(region.border)) : null, region.fill !== void 0 ? raw(el("a:fill", null, raw(genXmlColorSelection(region.fill)))) : null])) : null];
9650
- return el(`a:${name}`, null, children);
9651
- }
9652
- /**
9653
- * Build the `tcBdr` border block for a custom table style region.
9654
- * A single `BorderProps` styles all four sides plus the interior grid lines; a
9655
- * TRBL array styles only the four outer sides. Sides are emitted in schema order.
9656
- * @param {BorderProps | BorderProps[]} border - border definition
9657
- * @return {string} XML
9658
- */
9659
- function genXmlTableStyleBorders(border) {
9660
- let sides;
9661
- if (Array.isArray(border)) {
9662
- const [top, right, bottom, left] = border;
9663
- sides = [
9664
- ["left", left],
9665
- ["right", right],
9666
- ["top", top],
9667
- ["bottom", bottom]
9668
- ];
9669
- } else sides = [
9670
- ["left", border],
9671
- ["right", border],
9672
- ["top", border],
9673
- ["bottom", border],
9674
- ["insideH", border],
9675
- ["insideV", border]
9676
- ];
9677
- return el("a:tcBdr", null, sides.map(([side, b]) => {
9678
- if (!b) return null;
9679
- if (b.type === "none") return raw(el(`a:${side}`, null, raw(el("a:ln", null, raw(voidEl("a:noFill"))))));
9680
- return raw(el(`a:${side}`, null, raw(el("a:ln", {
9681
- w: lineWidthToEmu(resolveBorderWidth(b, 1)),
9682
- cap: "flat",
9683
- cmpd: "sng",
9684
- algn: "ctr"
9685
- }, [raw(genXmlColorSelection({
9686
- color: b.color ?? "666666",
9687
- transparency: b.transparency
9688
- })), raw(voidEl("a:prstDash", { val: b.type === "dash" ? "sysDash" : "solid" }))]))));
9689
- }));
9972
+ });
9690
9973
  }
9691
9974
  //#endregion
9692
9975
  //#region src/gen/slide/comments.ts
@@ -10333,7 +10616,7 @@ async function buildPackageParts(source, props) {
10333
10616
  zip.add("ppt/theme/theme2.xml", makeXmlTheme(pres));
10334
10617
  zip.add("ppt/presentation.xml", makeXmlPresentation(pres));
10335
10618
  zip.add("ppt/presProps.xml", makeXmlPresProps());
10336
- zip.add("ppt/tableStyles.xml", makeXmlTableStyles(source.tableStyles));
10619
+ zip.add("ppt/tableStyles.xml", makeXmlTableStyles());
10337
10620
  zip.add("ppt/viewProps.xml", makeXmlViewProps());
10338
10621
  pres.slideLayouts.forEach((layout, idx) => {
10339
10622
  zip.add(`ppt/slideLayouts/slideLayout${idx + 1}.xml`, makeXmlLayout(layout));
@@ -10444,7 +10727,7 @@ async function writePackage(source, props) {
10444
10727
  * @see https://docs.microsoft.com/en-us/office/open-xml/structure-of-a-presentationml-document
10445
10728
  * @see https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2010/hh273476(v=office.14)
10446
10729
  */
10447
- const VERSION = "1.0.0";
10730
+ const VERSION = "2.0.0";
10448
10731
  function standardLayoutToPresLayout(layout) {
10449
10732
  return {
10450
10733
  name: layout.name,
@@ -10600,7 +10883,6 @@ var PresentationCore = class {
10600
10883
  }
10601
10884
  /** custom document properties stored in docProps/custom.xml */
10602
10885
  _customProperties;
10603
- _tableStyles;
10604
10886
  /**
10605
10887
  * slide layout definition objects, used for generating slide layout files.
10606
10888
  * `protected` (not `private`) so the browser entry subclass can resolve
@@ -10679,7 +10961,6 @@ var PresentationCore = class {
10679
10961
  this._slides = [];
10680
10962
  this._sections = [];
10681
10963
  this._customProperties = [];
10682
- this._tableStyles = [];
10683
10964
  this._masterSlide = {
10684
10965
  addChart: null,
10685
10966
  addComment: null,
@@ -10746,7 +11027,6 @@ var PresentationCore = class {
10746
11027
  runtime: this._runtime,
10747
11028
  presentation: this.internalPresentation,
10748
11029
  customProperties: this._customProperties,
10749
- tableStyles: this._tableStyles,
10750
11030
  fontMetrics: this._fontMetrics
10751
11031
  };
10752
11032
  }
@@ -11193,31 +11473,6 @@ var PresentationCore = class {
11193
11473
  if (propsClone.background) addBackgroundDefinition(propsClone.background, newLayout);
11194
11474
  if (newLayout._slideNumberProps && !this._masterSlide._slideNumberProps) this._masterSlide._slideNumberProps = newLayout._slideNumberProps;
11195
11475
  }
11196
- /**
11197
- * Register a reusable custom table style and return its GUID.
11198
- * The style is written to `ppt/tableStyles.xml` and is editable in PowerPoint's
11199
- * Table Styles gallery. Pass the returned GUID as `TableProps.tableStyle`, and use
11200
- * the `has*` flags (`hasHeader`, `hasBandedRows`, …) to activate the matching regions.
11201
- * @param {TableStyleProps} props - custom table style definition (requires `name`)
11202
- * @returns {string} braced GUID to use as `tableStyle`
11203
- * @example
11204
- * const brand = pptx.defineTableStyle({
11205
- * name: 'Brand Banded',
11206
- * firstRow: { fill:'1A2B3C', color:'FFFFFF', bold:true },
11207
- * band1H: { fill:'EAF1F8' },
11208
- * })
11209
- * slide.addTable(rows, { tableStyle: brand, hasHeader:true, hasBandedRows:true })
11210
- */
11211
- defineTableStyle(props) {
11212
- if (!props || typeof props !== "object") throw new InvalidOptionError("table-style/missing-argument", "defineTableStyle() requires a `{ name, ... }` object argument");
11213
- if (!props.name || typeof props.name !== "string") throw new InvalidOptionError("table-style/missing-name", "defineTableStyle() requires a non-empty `name`");
11214
- const guid = `{${getUuid("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx").toUpperCase()}}`;
11215
- this._tableStyles.push({
11216
- guid,
11217
- def: props
11218
- });
11219
- return guid;
11220
- }
11221
11476
  };
11222
11477
  //#endregion
11223
11478
  //#region src/types/text.ts
@@ -11235,4 +11490,4 @@ function textRuns(runs) {
11235
11490
  //#endregion
11236
11491
  export { textRuns as n, PresentationCore as r, textRun as t };
11237
11492
 
11238
- //# sourceMappingURL=text-WRUbOy2r.js.map
11493
+ //# sourceMappingURL=text-B1ZrPEeK.js.map