@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.
- package/README.md +3 -1
- package/dist/browser.d.ts +5 -5
- package/dist/browser.js +2 -2
- package/dist/{diagnostics-DzY9Tyfm.d.ts → diagnostics-CQ0JWc9m.d.ts} +4 -21
- package/dist/{diagnostics-DzY9Tyfm.d.ts.map → diagnostics-CQ0JWc9m.d.ts.map} +1 -1
- package/dist/{errors-DRLpOpgQ.d.ts → errors-B22h8Qd0.d.ts} +3 -3
- package/dist/{errors-DRLpOpgQ.d.ts.map → errors-B22h8Qd0.d.ts.map} +1 -1
- package/dist/errors-DGE9zh3U.js.map +1 -1
- package/dist/{fit-CbxyHN69.js → fit-BSWY0AYt.js} +0 -0
- package/dist/{fit-CbxyHN69.js.map → fit-BSWY0AYt.js.map} +1 -1
- package/dist/{html-dom-wVa3TiG7.js → html-dom-BQLUntho.js} +2 -2
- package/dist/html-dom-BQLUntho.js.map +1 -0
- package/dist/html.d.ts +3 -3
- package/dist/html.js +1 -1
- package/dist/{image-size-C5Z1sKof.js → image-size-C8uYE8GJ.js} +3 -3
- package/dist/{image-size-C5Z1sKof.js.map → image-size-C8uYE8GJ.js.map} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/inspect.d.ts +1 -1
- package/dist/inspect.js +2 -2
- package/dist/math.d.ts +1 -1
- package/dist/math.js +2 -1
- package/dist/math.js.map +1 -1
- package/dist/measure.d.ts +2 -2
- package/dist/measure.js +1 -1
- package/dist/node.d.ts +5 -5
- package/dist/node.js +1 -1
- package/dist/{pres-5x1bjCzk.d.ts → pres-GU-jjBEx.d.ts} +2 -2
- package/dist/{pres-5x1bjCzk.d.ts.map → pres-GU-jjBEx.d.ts.map} +1 -1
- package/dist/{presentation-RGOiun5P.d.ts → presentation-CVaTZw1V.d.ts} +316 -18
- package/dist/presentation-CVaTZw1V.d.ts.map +1 -0
- package/dist/{presentation-B0JWdTN1.js → presentation-MJe9WDi4.js} +21 -27
- package/dist/presentation-MJe9WDi4.js.map +1 -0
- package/dist/read.d.ts +4 -4
- package/dist/read.js +2 -2
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +0 -0
- package/dist/script.js.map +1 -1
- package/dist/{shapes-BZU8UTW2.js → shapes-CaOgR0i1.js} +910 -22
- package/dist/shapes-CaOgR0i1.js.map +1 -0
- package/dist/{slide-B6mDaM-P.d.ts → slide-BBlElWr9.d.ts} +223 -92
- package/dist/slide-BBlElWr9.d.ts.map +1 -0
- package/dist/{text-WRUbOy2r.js → text-B1ZrPEeK.js} +441 -186
- package/dist/text-B1ZrPEeK.js.map +1 -0
- package/dist/zip.d.ts +1 -1
- package/package.json +9 -20
- package/dist/html-dom-wVa3TiG7.js.map +0 -1
- package/dist/presentation-B0JWdTN1.js.map +0 -1
- package/dist/presentation-RGOiun5P.d.ts.map +0 -1
- package/dist/shapes-BZU8UTW2.js.map +0 -1
- package/dist/slide-B6mDaM-P.d.ts.map +0 -1
- 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-
|
|
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-
|
|
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)
|
|
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
|
-
*
|
|
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),
|
|
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 =
|
|
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
|
-
|
|
2336
|
-
|
|
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[
|
|
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)
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
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
|
-
*
|
|
7487
|
-
*
|
|
7488
|
-
*
|
|
7489
|
-
* @param {BorderProps
|
|
7490
|
-
* @return {string}
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
9618
|
-
|
|
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(
|
|
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 = "
|
|
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-
|
|
11493
|
+
//# sourceMappingURL=text-B1ZrPEeK.js.map
|