@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as warn } from "./diagnostics-DYQC7xLV.js";
|
|
2
2
|
import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-DGE9zh3U.js";
|
|
3
|
-
import { r as getImageSizeFromBytes, t as fitSrcRectPercents } from "./image-size-
|
|
3
|
+
import { r as getImageSizeFromBytes, t as fitSrcRectPercents } from "./image-size-C8uYE8GJ.js";
|
|
4
4
|
import { DOMParser, MIME_TYPE, XMLSerializer, onErrorStopParsing } from "@xmldom/xmldom";
|
|
5
5
|
/** Parse an XML string strictly: any well-formedness error throws. */
|
|
6
6
|
function parseXml(xml) {
|
|
@@ -1484,7 +1484,6 @@ function applyColorTransforms(baseHex, transforms) {
|
|
|
1484
1484
|
if (f !== null) alpha = clamp01((alpha ?? 1) + f);
|
|
1485
1485
|
break;
|
|
1486
1486
|
}
|
|
1487
|
-
default: break;
|
|
1488
1487
|
}
|
|
1489
1488
|
return alpha === void 0 ? { hex: toHex(rgb) } : {
|
|
1490
1489
|
hex: toHex(rgb),
|
|
@@ -2011,6 +2010,38 @@ function readPictureFill(container, rels = null) {
|
|
|
2011
2010
|
};
|
|
2012
2011
|
}
|
|
2013
2012
|
//#endregion
|
|
2013
|
+
//#region src/read/api/pattern-fill.ts
|
|
2014
|
+
/**
|
|
2015
|
+
* Shared pattern-fill reader for DrawingML colour-bearing containers: a shape's `p:spPr`, a
|
|
2016
|
+
* slide's `p:bg/p:bgPr`, and a table's `a:tblPr` / cell's `a:tcPr`.
|
|
2017
|
+
*
|
|
2018
|
+
* `a:pattFill` is a preset hatch name plus two wrapped colours, and decoding it is three
|
|
2019
|
+
* lines — which is exactly why it had been open-coded in each place that needed it. Sharing
|
|
2020
|
+
* it is what keeps the three from drifting into different answers for the same element, the
|
|
2021
|
+
* same reason {@link import('./gradient.js').readGradientFill} and
|
|
2022
|
+
* {@link import('./picture-fill.js').readPictureFill} are shared.
|
|
2023
|
+
*/
|
|
2024
|
+
/**
|
|
2025
|
+
* Read a container's `a:pattFill`, or `null` when its fill is not a pattern.
|
|
2026
|
+
* @param {Element} container - the fill-bearing parent (`p:spPr`, `p:bgPr`, `a:tblPr`, `a:tcPr`, …)
|
|
2027
|
+
* @param {ColorContext} ctx - the theme colour context each colour resolves against
|
|
2028
|
+
* @returns {PatternFill | null} the decoded hatch, or `null`
|
|
2029
|
+
*/
|
|
2030
|
+
function readPatternFill(container, ctx) {
|
|
2031
|
+
const patt = firstChild(container, "a:pattFill");
|
|
2032
|
+
if (!patt) return null;
|
|
2033
|
+
const wrapColor = (qname) => {
|
|
2034
|
+
const wrap = firstChild(patt, qname);
|
|
2035
|
+
const colorEl = wrap && firstChildElement(wrap);
|
|
2036
|
+
return colorEl ? resolveColorElement(colorEl, ctx) : null;
|
|
2037
|
+
};
|
|
2038
|
+
return {
|
|
2039
|
+
preset: attr(patt, "prst") ?? null,
|
|
2040
|
+
foreground: wrapColor("a:fgClr"),
|
|
2041
|
+
background: wrapColor("a:bgClr")
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
//#endregion
|
|
2014
2045
|
//#region src/read/api/shapes/oxml.ts
|
|
2015
2046
|
/**
|
|
2016
2047
|
* Shape-element plumbing: the schema-successor lists that keep a get-or-added child in document
|
|
@@ -2910,9 +2941,7 @@ function readGeometryPath(path) {
|
|
|
2910
2941
|
swAng: (intValue(attr(seg, "swAng")) ?? 0) / 6e4
|
|
2911
2942
|
});
|
|
2912
2943
|
break;
|
|
2913
|
-
case "close":
|
|
2914
|
-
commands.push({ cmd: "close" });
|
|
2915
|
-
break;
|
|
2944
|
+
case "close": commands.push({ cmd: "close" });
|
|
2916
2945
|
}
|
|
2917
2946
|
}
|
|
2918
2947
|
return {
|
|
@@ -3491,19 +3520,7 @@ var Shape = class {
|
|
|
3491
3520
|
*/
|
|
3492
3521
|
get patternFill() {
|
|
3493
3522
|
const props = this.properties();
|
|
3494
|
-
|
|
3495
|
-
if (!patt) return null;
|
|
3496
|
-
const ctx = this.slide.themeContext();
|
|
3497
|
-
const resolveWrap = (qname) => {
|
|
3498
|
-
const wrap = firstChild(patt, qname);
|
|
3499
|
-
const colorEl = wrap && firstChildElement(wrap);
|
|
3500
|
-
return colorEl ? resolveColorElement(colorEl, ctx) : null;
|
|
3501
|
-
};
|
|
3502
|
-
return {
|
|
3503
|
-
preset: attr(patt, "prst") ?? null,
|
|
3504
|
-
foreground: resolveWrap("a:fgClr"),
|
|
3505
|
-
background: resolveWrap("a:bgClr")
|
|
3506
|
-
};
|
|
3523
|
+
return props ? readPatternFill(props, this.slide.themeContext()) : null;
|
|
3507
3524
|
}
|
|
3508
3525
|
/**
|
|
3509
3526
|
* The shape's picture (image) fill (`spPr/a:blipFill`), or `null` when the fill
|
|
@@ -4715,6 +4732,452 @@ function toNumberOrNull(value) {
|
|
|
4715
4732
|
return Number.isFinite(number) ? number : null;
|
|
4716
4733
|
}
|
|
4717
4734
|
//#endregion
|
|
4735
|
+
//#region src/read/api/table-edit.ts
|
|
4736
|
+
/**
|
|
4737
|
+
* Ordered mutation of a table cell's `a:tcPr`, and the schema facts every such edit needs.
|
|
4738
|
+
*
|
|
4739
|
+
* `CT_TableCellProperties` declares its children as a **sequence**, so an append-only
|
|
4740
|
+
* implementation produces an out-of-order `a:tcPr` — which PowerPoint reports as a corrupt
|
|
4741
|
+
* file rather than as a bad edit. Every insertion therefore goes through
|
|
4742
|
+
* {@link getOrAddChild} / {@link insertInOrder} with the new element's *successors*, which
|
|
4743
|
+
* is what {@link TCPR_AFTER} tabulates. Writing that table once, here, is the point of this
|
|
4744
|
+
* module: a setter that hand-rolls its own successor list is one rename away from silently
|
|
4745
|
+
* producing an invalid part.
|
|
4746
|
+
*
|
|
4747
|
+
* The attribute values are the other half. A value outside its `ST_` union is equally fatal
|
|
4748
|
+
* and equally silent, so each is checked against the enum before it is written — the same
|
|
4749
|
+
* validate-at-the-boundary rule the write path follows, with the difference that here there
|
|
4750
|
+
* is a caller to throw at rather than a deck to degrade.
|
|
4751
|
+
*/
|
|
4752
|
+
/**
|
|
4753
|
+
* `CT_TableCellProperties`' child sequence, in declaration order.
|
|
4754
|
+
* @see ECMA-376 Part 1 §21.1.3.17 (`a:tcPr`)
|
|
4755
|
+
*/
|
|
4756
|
+
const TCPR_SEQUENCE = [
|
|
4757
|
+
"a:lnL",
|
|
4758
|
+
"a:lnR",
|
|
4759
|
+
"a:lnT",
|
|
4760
|
+
"a:lnB",
|
|
4761
|
+
"a:lnTlToBr",
|
|
4762
|
+
"a:lnBlToTr",
|
|
4763
|
+
"a:cell3D",
|
|
4764
|
+
"a:noFill",
|
|
4765
|
+
"a:solidFill",
|
|
4766
|
+
"a:gradFill",
|
|
4767
|
+
"a:blipFill",
|
|
4768
|
+
"a:pattFill",
|
|
4769
|
+
"a:grpFill",
|
|
4770
|
+
"a:headers",
|
|
4771
|
+
"a:extLst"
|
|
4772
|
+
];
|
|
4773
|
+
/**
|
|
4774
|
+
* For each `a:tcPr` child, the children that must follow it — i.e. what a new one is
|
|
4775
|
+
* inserted *before*. Derived from {@link TCPR_SEQUENCE} rather than written out, so the two
|
|
4776
|
+
* cannot disagree and adding a child to the sequence updates every successor list at once.
|
|
4777
|
+
*/
|
|
4778
|
+
const TCPR_AFTER = Object.fromEntries(TCPR_SEQUENCE.map((qname, index) => [qname, TCPR_SEQUENCE.slice(index + 1)]));
|
|
4779
|
+
/** The four edges plus the two diagonals, keyed as {@link TableCellEdge} names them. */
|
|
4780
|
+
const EDGE_QNAMES = {
|
|
4781
|
+
left: "a:lnL",
|
|
4782
|
+
right: "a:lnR",
|
|
4783
|
+
top: "a:lnT",
|
|
4784
|
+
bottom: "a:lnB",
|
|
4785
|
+
tlToBr: "a:lnTlToBr",
|
|
4786
|
+
blToTr: "a:lnBlToTr"
|
|
4787
|
+
};
|
|
4788
|
+
/** `ST_TextAnchoringType` — `a:tcPr/@anchor`. */
|
|
4789
|
+
const ANCHOR_VALUES = [
|
|
4790
|
+
"t",
|
|
4791
|
+
"ctr",
|
|
4792
|
+
"b",
|
|
4793
|
+
"just",
|
|
4794
|
+
"dist"
|
|
4795
|
+
];
|
|
4796
|
+
/** `ST_TextVerticalType` — `a:tcPr/@vert`. */
|
|
4797
|
+
const VERT_VALUES = [
|
|
4798
|
+
"horz",
|
|
4799
|
+
"vert",
|
|
4800
|
+
"vert270",
|
|
4801
|
+
"wordArtVert",
|
|
4802
|
+
"eaVert",
|
|
4803
|
+
"mongolianVert",
|
|
4804
|
+
"wordArtVertRtl"
|
|
4805
|
+
];
|
|
4806
|
+
/** `ST_TextHorzOverflowType` — `a:tcPr/@horzOverflow`. */
|
|
4807
|
+
const HORZ_OVERFLOW_VALUES = ["clip", "overflow"];
|
|
4808
|
+
/**
|
|
4809
|
+
* Check a value against its `ST_` union, throwing when it is outside.
|
|
4810
|
+
*
|
|
4811
|
+
* Throwing rather than warn-and-drop, which is the opposite of what the *write* path does
|
|
4812
|
+
* with the same enums — and deliberately so. On the write path an option comes from a deck
|
|
4813
|
+
* being built, and dropping one value is better than failing a whole build; here it comes
|
|
4814
|
+
* from a caller editing one attribute, so silently doing nothing would leave them looking at
|
|
4815
|
+
* an unchanged deck with no explanation.
|
|
4816
|
+
*
|
|
4817
|
+
* @param {string} value - the value the caller asked for
|
|
4818
|
+
* @param {readonly string[]} valid - the enum's members
|
|
4819
|
+
* @param {string} attribute - the attribute's name, for the message
|
|
4820
|
+
* @param {InvalidOptionErrorCode} code - the condition to report
|
|
4821
|
+
* @returns {string} `value`, when it is legal
|
|
4822
|
+
*/
|
|
4823
|
+
function checkEnum(value, valid, attribute, code) {
|
|
4824
|
+
if (valid.includes(value)) return value;
|
|
4825
|
+
throw new InvalidOptionError(code, `Invalid ${attribute}: ${JSON.stringify(value)}. Expected one of: ${valid.join(", ")}.`);
|
|
4826
|
+
}
|
|
4827
|
+
/**
|
|
4828
|
+
* Get or create a child of `a:tcPr` at its schema position.
|
|
4829
|
+
* @param {Element} tcPr - the cell's properties element
|
|
4830
|
+
* @param {string} qname - the child to get or create
|
|
4831
|
+
* @returns {Element} the existing or newly-inserted child
|
|
4832
|
+
*/
|
|
4833
|
+
function tcPrChild(tcPr, qname) {
|
|
4834
|
+
return getOrAddChild(tcPr, qname, TCPR_AFTER[qname] ?? []);
|
|
4835
|
+
}
|
|
4836
|
+
/**
|
|
4837
|
+
* Insert an already-built subtree into `a:tcPr` at its schema position.
|
|
4838
|
+
* @param {Element} tcPr - the cell's properties element
|
|
4839
|
+
* @param {string} qname - the qname of the node being inserted (decides where it goes)
|
|
4840
|
+
* @param {Element} node - the subtree to insert
|
|
4841
|
+
*/
|
|
4842
|
+
function insertTcPrChild(tcPr, qname, node) {
|
|
4843
|
+
insertInOrder(tcPr, node, TCPR_AFTER[qname] ?? []);
|
|
4844
|
+
}
|
|
4845
|
+
/**
|
|
4846
|
+
* Round a measurement to whole EMU, rejecting a value that cannot be written.
|
|
4847
|
+
* `NaN`/`Infinity` would reach the attribute verbatim and make the part invalid, which is
|
|
4848
|
+
* exactly the "silent coercion of invalid input" the project's policy rules out.
|
|
4849
|
+
*/
|
|
4850
|
+
function checkFiniteEmu(value, field, code) {
|
|
4851
|
+
if (!Number.isFinite(value)) throw new InvalidOptionError(code, `${field} must be a finite number of EMU, got: ${String(value)}`);
|
|
4852
|
+
return Math.round(value);
|
|
4853
|
+
}
|
|
4854
|
+
//#endregion
|
|
4855
|
+
//#region src/read/api/table-structure.ts
|
|
4856
|
+
/**
|
|
4857
|
+
* Structural edits to an existing `a:tbl`: adding and removing rows and columns, and
|
|
4858
|
+
* merging and unmerging cells.
|
|
4859
|
+
*
|
|
4860
|
+
* The one fact that makes this tractable is that a stored table's grid is already
|
|
4861
|
+
* **rectangular**. Unlike the write path — which receives lopsided row arrays and has to
|
|
4862
|
+
* build the merge grid itself (`gen/slide/objects/table.ts` STEP 3) — every `a:tr` in a
|
|
4863
|
+
* conformant `a:tbl` holds exactly one `a:tc` per grid column, with the covered half of each
|
|
4864
|
+
* span present and flagged. So "the cell at (r, c)" is simply the c-th `a:tc` of the r-th
|
|
4865
|
+
* `a:tr`, and an edit's whole job is keeping that rectangle true.
|
|
4866
|
+
*
|
|
4867
|
+
* Three things have to stay in step, and every function here is written around them:
|
|
4868
|
+
*
|
|
4869
|
+
* 1. `a:tblGrid/a:gridCol` count == each row's `a:tc` count.
|
|
4870
|
+
* 2. A cell with `@gridSpan="n"` is followed by exactly `n-1` cells carrying `@hMerge="1"`,
|
|
4871
|
+
* and a cell with `@rowSpan="n"` is under-hung by `n-1` cells carrying `@vMerge="1"`, in
|
|
4872
|
+
* the same columns.
|
|
4873
|
+
* 3. A covered cell carries no span attributes of its own — its extent is the origin's.
|
|
4874
|
+
*
|
|
4875
|
+
* Breaking any of them produces a table PowerPoint reports as a corrupt file rather than as
|
|
4876
|
+
* a bad edit, which is why the span bookkeeping here is explicit rather than incidental.
|
|
4877
|
+
*/
|
|
4878
|
+
/** Every `a:tr` of a table, in document order. */
|
|
4879
|
+
function rowsOf(tbl) {
|
|
4880
|
+
return getElements(tbl, "a:tr");
|
|
4881
|
+
}
|
|
4882
|
+
/** Every `a:tc` of a row, in document (left-to-right) order. */
|
|
4883
|
+
function cellsOf(tr) {
|
|
4884
|
+
return getElements(tr, "a:tc");
|
|
4885
|
+
}
|
|
4886
|
+
/** The table's `a:tblGrid`, or a thrown error — `CT_Table` requires one. */
|
|
4887
|
+
function gridOf(tbl) {
|
|
4888
|
+
const grid = firstChild(tbl, "a:tblGrid");
|
|
4889
|
+
if (!grid) throw new InvalidOptionError("table/column-index-out-of-range", "This table has no a:tblGrid, so its columns cannot be edited");
|
|
4890
|
+
return grid;
|
|
4891
|
+
}
|
|
4892
|
+
/** A cell's `@gridSpan`, defaulting to 1. */
|
|
4893
|
+
function gridSpanOf(tc) {
|
|
4894
|
+
return intValue(attr(tc, "gridSpan")) ?? 1;
|
|
4895
|
+
}
|
|
4896
|
+
/** A cell's `@rowSpan`, defaulting to 1. */
|
|
4897
|
+
function rowSpanOf(tc) {
|
|
4898
|
+
return intValue(attr(tc, "rowSpan")) ?? 1;
|
|
4899
|
+
}
|
|
4900
|
+
/** Whether a cell is the covered half of a horizontal merge. */
|
|
4901
|
+
function isHMerge(tc) {
|
|
4902
|
+
return attr(tc, "hMerge") === "1" || attr(tc, "hMerge") === "true";
|
|
4903
|
+
}
|
|
4904
|
+
/** Whether a cell is the covered half of a vertical merge. */
|
|
4905
|
+
function isVMerge(tc) {
|
|
4906
|
+
return attr(tc, "vMerge") === "1" || attr(tc, "vMerge") === "true";
|
|
4907
|
+
}
|
|
4908
|
+
/**
|
|
4909
|
+
* Set a span attribute, removing it when the span collapses to 1 — the schema default, and
|
|
4910
|
+
* what PowerPoint itself writes for an unmerged cell.
|
|
4911
|
+
*/
|
|
4912
|
+
function setSpan(tc, name, value) {
|
|
4913
|
+
if (value <= 1) removeAttr(tc, name);
|
|
4914
|
+
else setAttr(tc, name, String(value));
|
|
4915
|
+
}
|
|
4916
|
+
/**
|
|
4917
|
+
* Walk left from `col` to the origin of the horizontal run containing it.
|
|
4918
|
+
* A run is an origin followed by its `hMerge` continuations, so the origin is the first
|
|
4919
|
+
* cell at or left of `col` that is not one.
|
|
4920
|
+
* @returns the origin's column index, or `col` itself when the cell stands alone
|
|
4921
|
+
*/
|
|
4922
|
+
function hRunOrigin(cells, col) {
|
|
4923
|
+
let idx = col;
|
|
4924
|
+
while (idx > 0) {
|
|
4925
|
+
const cell = cells[idx];
|
|
4926
|
+
if (!cell || !isHMerge(cell)) break;
|
|
4927
|
+
idx -= 1;
|
|
4928
|
+
}
|
|
4929
|
+
return idx;
|
|
4930
|
+
}
|
|
4931
|
+
/**
|
|
4932
|
+
* Walk up from `row` to the origin of the vertical run containing `(row, col)`.
|
|
4933
|
+
* @returns the origin's row index, or `row` itself when the cell stands alone
|
|
4934
|
+
*/
|
|
4935
|
+
function vRunOrigin(rows, row, col) {
|
|
4936
|
+
let idx = row;
|
|
4937
|
+
while (idx > 0) {
|
|
4938
|
+
const cell = rows[idx]?.[col];
|
|
4939
|
+
if (!cell || !isVMerge(cell)) break;
|
|
4940
|
+
idx -= 1;
|
|
4941
|
+
}
|
|
4942
|
+
return idx;
|
|
4943
|
+
}
|
|
4944
|
+
/** A fresh, empty `a:tc`, shaped the way PowerPoint writes one. */
|
|
4945
|
+
function makeCell(doc) {
|
|
4946
|
+
const tc = createElement(doc, "a:tc");
|
|
4947
|
+
const txBody = createElement(doc, "a:txBody");
|
|
4948
|
+
txBody.appendChild(createElement(doc, "a:bodyPr"));
|
|
4949
|
+
txBody.appendChild(createElement(doc, "a:lstStyle"));
|
|
4950
|
+
txBody.appendChild(createElement(doc, "a:p"));
|
|
4951
|
+
tc.appendChild(txBody);
|
|
4952
|
+
tc.appendChild(createElement(doc, "a:tcPr"));
|
|
4953
|
+
return tc;
|
|
4954
|
+
}
|
|
4955
|
+
/** The grid as a row-major array of `a:tc` elements. */
|
|
4956
|
+
function gridOfCells(tbl) {
|
|
4957
|
+
return rowsOf(tbl).map((tr) => cellsOf(tr));
|
|
4958
|
+
}
|
|
4959
|
+
/** Guard an index against `[0, limit]` (inclusive upper bound, for insertion points). */
|
|
4960
|
+
function checkIndex(index, limit, what, inclusive) {
|
|
4961
|
+
const max = inclusive ? limit : limit - 1;
|
|
4962
|
+
if (!Number.isInteger(index) || index < 0 || index > max) throw new InvalidOptionError(what === "row" ? "table/row-index-out-of-range" : "table/column-index-out-of-range", `${what} index ${String(index)} is out of range (expected 0..${max})`);
|
|
4963
|
+
return index;
|
|
4964
|
+
}
|
|
4965
|
+
/**
|
|
4966
|
+
* Insert a row at `index` (default: append).
|
|
4967
|
+
*
|
|
4968
|
+
* The subtle case is inserting **through** a vertical merge. If the row currently at `index`
|
|
4969
|
+
* holds a `vMerge` continuation in some column, the span it belongs to straddles the
|
|
4970
|
+
* insertion point — so the new row must continue that span rather than interrupt it: the
|
|
4971
|
+
* origin's `@rowSpan` grows by one and the new cell is another continuation. Interrupting it
|
|
4972
|
+
* instead would leave an origin claiming more rows than it has continuations, which is the
|
|
4973
|
+
* corrupt-file case.
|
|
4974
|
+
*/
|
|
4975
|
+
function insertRow(tbl, index) {
|
|
4976
|
+
const rows = rowsOf(tbl);
|
|
4977
|
+
const at = index === void 0 ? rows.length : checkIndex(index, rows.length, "row", true);
|
|
4978
|
+
const grid = gridOfCells(tbl);
|
|
4979
|
+
const colCount = getElements(gridOf(tbl), "a:gridCol").length;
|
|
4980
|
+
const doc = ownerDocumentOf(tbl);
|
|
4981
|
+
const tr = createElement(doc, "a:tr");
|
|
4982
|
+
setAttr(tr, "h", "0");
|
|
4983
|
+
for (let col = 0; col < colCount; col++) {
|
|
4984
|
+
const tc = makeCell(doc);
|
|
4985
|
+
const displaced = grid[at]?.[col];
|
|
4986
|
+
if (displaced && isVMerge(displaced)) {
|
|
4987
|
+
const origin = grid[vRunOrigin(grid, at, col)]?.[col];
|
|
4988
|
+
if (origin) setSpan(origin, "rowSpan", rowSpanOf(origin) + 1);
|
|
4989
|
+
setAttr(tc, "vMerge", "1");
|
|
4990
|
+
if (isHMerge(displaced)) setAttr(tc, "hMerge", "1");
|
|
4991
|
+
const span = gridSpanOf(displaced);
|
|
4992
|
+
if (span > 1) setSpan(tc, "gridSpan", span);
|
|
4993
|
+
}
|
|
4994
|
+
tr.appendChild(tc);
|
|
4995
|
+
}
|
|
4996
|
+
const before = rows[at] ?? null;
|
|
4997
|
+
tbl.insertBefore(tr, before);
|
|
4998
|
+
return tr;
|
|
4999
|
+
}
|
|
5000
|
+
/**
|
|
5001
|
+
* Remove the row at `index`.
|
|
5002
|
+
*
|
|
5003
|
+
* Two span cases, and they pull in opposite directions. A cell in this row that *continues*
|
|
5004
|
+
* a span from above shortens that span by one. A cell in this row that *starts* one cannot
|
|
5005
|
+
* simply take its span away — the rows below still hold its continuations — so the first
|
|
5006
|
+
* continuation is promoted to origin and inherits the remaining extent. Its content is gone
|
|
5007
|
+
* with the row, which is inherent to removing a row rather than a choice made here.
|
|
5008
|
+
*/
|
|
5009
|
+
function removeRow(tbl, index) {
|
|
5010
|
+
const rows = rowsOf(tbl);
|
|
5011
|
+
const at = checkIndex(index, rows.length, "row", false);
|
|
5012
|
+
const grid = gridOfCells(tbl);
|
|
5013
|
+
const row = grid[at] ?? [];
|
|
5014
|
+
for (let col = 0; col < row.length; col++) {
|
|
5015
|
+
const tc = row[col];
|
|
5016
|
+
if (!tc) continue;
|
|
5017
|
+
if (isVMerge(tc)) {
|
|
5018
|
+
const origin = grid[vRunOrigin(grid, at, col)]?.[col];
|
|
5019
|
+
if (origin) setSpan(origin, "rowSpan", rowSpanOf(origin) - 1);
|
|
5020
|
+
continue;
|
|
5021
|
+
}
|
|
5022
|
+
const span = rowSpanOf(tc);
|
|
5023
|
+
if (span > 1) {
|
|
5024
|
+
const heir = grid[at + 1]?.[col];
|
|
5025
|
+
if (heir) {
|
|
5026
|
+
removeAttr(heir, "vMerge");
|
|
5027
|
+
setSpan(heir, "rowSpan", span - 1);
|
|
5028
|
+
setSpan(heir, "gridSpan", gridSpanOf(tc));
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
const tr = rows[at];
|
|
5033
|
+
if (tr) tbl.removeChild(tr);
|
|
5034
|
+
}
|
|
5035
|
+
/**
|
|
5036
|
+
* Insert a column at `index` (default: append), `widthEmu` wide.
|
|
5037
|
+
*
|
|
5038
|
+
* Mirrors {@link insertRow}'s split case on the other axis: when the cell currently at
|
|
5039
|
+
* `index` is an `hMerge` continuation, the insertion point falls inside a horizontal span,
|
|
5040
|
+
* so the span widens by one and the new cell joins it as another continuation.
|
|
5041
|
+
*/
|
|
5042
|
+
function insertColumn(tbl, index, widthEmu = 914400) {
|
|
5043
|
+
const grid = gridOf(tbl);
|
|
5044
|
+
const cols = getElements(grid, "a:gridCol");
|
|
5045
|
+
const at = index === void 0 ? cols.length : checkIndex(index, cols.length, "column", true);
|
|
5046
|
+
const doc = ownerDocumentOf(tbl);
|
|
5047
|
+
const gridCol = createElement(doc, "a:gridCol");
|
|
5048
|
+
setAttr(gridCol, "w", String(Math.round(widthEmu)));
|
|
5049
|
+
grid.insertBefore(gridCol, cols[at] ?? null);
|
|
5050
|
+
for (const tr of rowsOf(tbl)) {
|
|
5051
|
+
const cells = cellsOf(tr);
|
|
5052
|
+
const tc = makeCell(doc);
|
|
5053
|
+
const displaced = cells[at];
|
|
5054
|
+
if (displaced && isHMerge(displaced)) {
|
|
5055
|
+
const origin = cells[hRunOrigin(cells, at)];
|
|
5056
|
+
if (origin) setSpan(origin, "gridSpan", gridSpanOf(origin) + 1);
|
|
5057
|
+
setAttr(tc, "hMerge", "1");
|
|
5058
|
+
if (isVMerge(displaced)) setAttr(tc, "vMerge", "1");
|
|
5059
|
+
const span = rowSpanOf(displaced);
|
|
5060
|
+
if (span > 1) setSpan(tc, "rowSpan", span);
|
|
5061
|
+
}
|
|
5062
|
+
tr.insertBefore(tc, cells[at] ?? firstChild(tr, "a:extLst"));
|
|
5063
|
+
}
|
|
5064
|
+
return gridCol;
|
|
5065
|
+
}
|
|
5066
|
+
/**
|
|
5067
|
+
* Remove the column at `index`.
|
|
5068
|
+
*
|
|
5069
|
+
* When the column falls inside a horizontal span, the span shrinks by one and a
|
|
5070
|
+
* *continuation* is removed rather than the origin — so the merged region narrows but keeps
|
|
5071
|
+
* its content. Only a column whose cell stands alone loses that cell outright.
|
|
5072
|
+
*/
|
|
5073
|
+
function removeColumn(tbl, index) {
|
|
5074
|
+
const grid = gridOf(tbl);
|
|
5075
|
+
const cols = getElements(grid, "a:gridCol");
|
|
5076
|
+
const at = checkIndex(index, cols.length, "column", false);
|
|
5077
|
+
const col = cols[at];
|
|
5078
|
+
if (col) grid.removeChild(col);
|
|
5079
|
+
for (const tr of rowsOf(tbl)) {
|
|
5080
|
+
const cells = cellsOf(tr);
|
|
5081
|
+
const originIdx = hRunOrigin(cells, at);
|
|
5082
|
+
const origin = cells[originIdx];
|
|
5083
|
+
if (!origin) continue;
|
|
5084
|
+
const span = gridSpanOf(origin);
|
|
5085
|
+
if (span > 1) {
|
|
5086
|
+
setSpan(origin, "gridSpan", span - 1);
|
|
5087
|
+
const victim = cells[originIdx + span - 1];
|
|
5088
|
+
if (victim) tr.removeChild(victim);
|
|
5089
|
+
continue;
|
|
5090
|
+
}
|
|
5091
|
+
const tc = cells[at];
|
|
5092
|
+
if (tc) tr.removeChild(tc);
|
|
5093
|
+
}
|
|
5094
|
+
}
|
|
5095
|
+
/**
|
|
5096
|
+
* Merge the rectangle `(row1, col1)`–`(row2, col2)` into one cell.
|
|
5097
|
+
*
|
|
5098
|
+
* The top-left cell becomes the origin and keeps its content; every other cell in the
|
|
5099
|
+
* rectangle becomes a covered cell — flagged, stripped of its own span attributes, and
|
|
5100
|
+
* emptied, since a covered cell is never rendered.
|
|
5101
|
+
*
|
|
5102
|
+
* A rectangle whose boundary **cuts through** an existing merge is rejected rather than
|
|
5103
|
+
* silently widened. Widening would be the friendlier-looking choice and the wrong one: the
|
|
5104
|
+
* caller asked for a specific region, and quietly returning a different one is how a layout
|
|
5105
|
+
* ends up subtly wrong with nothing to point at.
|
|
5106
|
+
*/
|
|
5107
|
+
function mergeCells(tbl, row1, col1, row2, col2) {
|
|
5108
|
+
const grid = gridOfCells(tbl);
|
|
5109
|
+
const rowCount = grid.length;
|
|
5110
|
+
const colCount = getElements(gridOf(tbl), "a:gridCol").length;
|
|
5111
|
+
const r1 = Math.min(row1, row2);
|
|
5112
|
+
const r2 = Math.max(row1, row2);
|
|
5113
|
+
const c1 = Math.min(col1, col2);
|
|
5114
|
+
const c2 = Math.max(col1, col2);
|
|
5115
|
+
checkIndex(r1, rowCount, "row", false);
|
|
5116
|
+
checkIndex(r2, rowCount, "row", false);
|
|
5117
|
+
checkIndex(c1, colCount, "column", false);
|
|
5118
|
+
checkIndex(c2, colCount, "column", false);
|
|
5119
|
+
if (r1 === r2 && c1 === c2) throw new InvalidOptionError("table/merge-range-invalid", "A merge needs at least two cells; the given range covers one");
|
|
5120
|
+
for (let r = r1; r <= r2; r++) for (let c = c1; c <= c2; c++) {
|
|
5121
|
+
if (!grid[r]?.[c]) continue;
|
|
5122
|
+
const originRow = vRunOrigin(grid, r, c);
|
|
5123
|
+
const originCol = hRunOrigin(grid[r] ?? [], c);
|
|
5124
|
+
const origin = grid[originRow]?.[originCol];
|
|
5125
|
+
if (!origin) continue;
|
|
5126
|
+
if (originRow < r1 || originCol < c1) throw new InvalidOptionError("table/merge-range-invalid", `The range (${r1},${c1})-(${r2},${c2}) starts inside an existing merged cell at (${originRow},${originCol}); unmerge it first`);
|
|
5127
|
+
if (originRow + rowSpanOf(origin) - 1 > r2 || originCol + gridSpanOf(origin) - 1 > c2) throw new InvalidOptionError("table/merge-range-invalid", `The range (${r1},${c1})-(${r2},${c2}) cuts through an existing merged cell at (${originRow},${originCol}); unmerge it first`);
|
|
5128
|
+
}
|
|
5129
|
+
const origin = grid[r1]?.[c1];
|
|
5130
|
+
if (!origin) return;
|
|
5131
|
+
setSpan(origin, "gridSpan", c2 - c1 + 1);
|
|
5132
|
+
setSpan(origin, "rowSpan", r2 - r1 + 1);
|
|
5133
|
+
removeAttr(origin, "hMerge");
|
|
5134
|
+
removeAttr(origin, "vMerge");
|
|
5135
|
+
for (let r = r1; r <= r2; r++) for (let c = c1; c <= c2; c++) {
|
|
5136
|
+
if (r === r1 && c === c1) continue;
|
|
5137
|
+
const tc = grid[r]?.[c];
|
|
5138
|
+
if (!tc) continue;
|
|
5139
|
+
removeAttr(tc, "gridSpan");
|
|
5140
|
+
removeAttr(tc, "rowSpan");
|
|
5141
|
+
if (c > c1) setAttr(tc, "hMerge", "1");
|
|
5142
|
+
else removeAttr(tc, "hMerge");
|
|
5143
|
+
if (r > r1) setAttr(tc, "vMerge", "1");
|
|
5144
|
+
else removeAttr(tc, "vMerge");
|
|
5145
|
+
emptyCellText(tc);
|
|
5146
|
+
}
|
|
5147
|
+
}
|
|
5148
|
+
/**
|
|
5149
|
+
* Split the merged cell whose origin is `(row, col)` back into individual cells.
|
|
5150
|
+
* The origin keeps its content; the cells it covered come back empty, which is what they
|
|
5151
|
+
* already were.
|
|
5152
|
+
*/
|
|
5153
|
+
function unmergeCell(tbl, row, col) {
|
|
5154
|
+
const grid = gridOfCells(tbl);
|
|
5155
|
+
checkIndex(row, grid.length, "row", false);
|
|
5156
|
+
checkIndex(col, getElements(gridOf(tbl), "a:gridCol").length, "column", false);
|
|
5157
|
+
const origin = grid[row]?.[col];
|
|
5158
|
+
if (!origin) return;
|
|
5159
|
+
if (isHMerge(origin) || isVMerge(origin)) throw new InvalidOptionError("table/merge-range-invalid", `The cell at (${row},${col}) is a covered cell, not a merge origin; unmerge the origin at (${vRunOrigin(grid, row, col)},${hRunOrigin(grid[row] ?? [], col)}) instead`);
|
|
5160
|
+
const rowSpan = rowSpanOf(origin);
|
|
5161
|
+
const gridSpan = gridSpanOf(origin);
|
|
5162
|
+
if (rowSpan === 1 && gridSpan === 1) return;
|
|
5163
|
+
removeAttr(origin, "gridSpan");
|
|
5164
|
+
removeAttr(origin, "rowSpan");
|
|
5165
|
+
for (let r = row; r < row + rowSpan; r++) for (let c = col; c < col + gridSpan; c++) {
|
|
5166
|
+
if (r === row && c === col) continue;
|
|
5167
|
+
const tc = grid[r]?.[c];
|
|
5168
|
+
if (!tc) continue;
|
|
5169
|
+
removeAttr(tc, "hMerge");
|
|
5170
|
+
removeAttr(tc, "vMerge");
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
5173
|
+
/** Reduce a cell's text body to a single empty paragraph. */
|
|
5174
|
+
function emptyCellText(tc) {
|
|
5175
|
+
const txBody = firstChild(tc, "a:txBody");
|
|
5176
|
+
if (!txBody) return;
|
|
5177
|
+
for (const p of getElements(txBody, "a:p")) txBody.removeChild(p);
|
|
5178
|
+
txBody.appendChild(createElement(ownerDocumentOf(txBody), "a:p"));
|
|
5179
|
+
}
|
|
5180
|
+
//#endregion
|
|
4718
5181
|
//#region src/read/api/table-style-resolve.ts
|
|
4719
5182
|
const TABLE_STYLES_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml";
|
|
4720
5183
|
/**
|
|
@@ -4893,6 +5356,63 @@ var Table = class {
|
|
|
4893
5356
|
const id = (tblPr && firstChild(tblPr, "a:tableStyleId"))?.textContent?.trim();
|
|
4894
5357
|
return id ? id : null;
|
|
4895
5358
|
}
|
|
5359
|
+
/**
|
|
5360
|
+
* The table's own background (`a:tblPr` fill) resolved against the slide's theme colour
|
|
5361
|
+
* context to a literal hex, or `null` when the table carries no solid background.
|
|
5362
|
+
*
|
|
5363
|
+
* This is the table-level counterpart of {@link TableCell.resolvedFill}, and it is a
|
|
5364
|
+
* genuinely different thing from a cell fill: a `a:tblPr` fill sits *behind* the grid, so
|
|
5365
|
+
* a cell with no fill of its own shows it through. Reports `null` for a non-solid choice
|
|
5366
|
+
* (`a:blipFill`/`a:gradFill`/`a:pattFill`/`a:noFill`) — read {@link pictureFill} for an
|
|
5367
|
+
* image background — and `null` with no theme context.
|
|
5368
|
+
*/
|
|
5369
|
+
get resolvedFill() {
|
|
5370
|
+
if (!this.themeColors) return null;
|
|
5371
|
+
const tblPr = firstChild(this.tbl, "a:tblPr");
|
|
5372
|
+
if (!tblPr || !FILL_CHOICES.some((q) => firstChild(tblPr, q))) return null;
|
|
5373
|
+
return resolveSolidFillColor(tblPr, this.themeColors);
|
|
5374
|
+
}
|
|
5375
|
+
/**
|
|
5376
|
+
* The table's picture background (`a:tblPr/a:blipFill`), or `null` when the table is not
|
|
5377
|
+
* image-backed. The table-level twin of {@link TableCell.pictureFill}, and needed for the
|
|
5378
|
+
* same reason: {@link resolvedFill} decodes only solid colours, so without this an
|
|
5379
|
+
* image-backed table is indistinguishable from an unfilled one.
|
|
5380
|
+
*/
|
|
5381
|
+
get pictureFill() {
|
|
5382
|
+
const tblPr = firstChild(this.tbl, "a:tblPr");
|
|
5383
|
+
return tblPr ? readPictureFill(tblPr, this.rels ?? null) : null;
|
|
5384
|
+
}
|
|
5385
|
+
/**
|
|
5386
|
+
* The table's gradient background (`a:tblPr/a:gradFill`), or `null` when it is not
|
|
5387
|
+
* gradient-filled. Needed for the same reason {@link pictureFill} is:
|
|
5388
|
+
* {@link resolvedFill} decodes only solid colours.
|
|
5389
|
+
*/
|
|
5390
|
+
get gradientFill() {
|
|
5391
|
+
if (!this.themeColors) return null;
|
|
5392
|
+
const tblPr = firstChild(this.tbl, "a:tblPr");
|
|
5393
|
+
return tblPr ? readGradientFill(tblPr, this.themeColors) : null;
|
|
5394
|
+
}
|
|
5395
|
+
/**
|
|
5396
|
+
* The table's pattern (hatch) background (`a:tblPr/a:pattFill`), or `null` when it is not
|
|
5397
|
+
* pattern-filled.
|
|
5398
|
+
*/
|
|
5399
|
+
get patternFill() {
|
|
5400
|
+
if (!this.themeColors) return null;
|
|
5401
|
+
const tblPr = firstChild(this.tbl, "a:tblPr");
|
|
5402
|
+
return tblPr ? readPatternFill(tblPr, this.themeColors) : null;
|
|
5403
|
+
}
|
|
5404
|
+
/**
|
|
5405
|
+
* The raw `schemeClr` token of the table's own background
|
|
5406
|
+
* (`a:tblPr/a:solidFill/a:schemeClr/@val`), or `null` for an absent or `srgbClr` fill.
|
|
5407
|
+
* {@link resolvedFill} is the literal it resolves to; this is the unresolved reference,
|
|
5408
|
+
* which is what a replica should carry so the copy still tracks its theme.
|
|
5409
|
+
*/
|
|
5410
|
+
get fillSchemeColor() {
|
|
5411
|
+
const tblPr = firstChild(this.tbl, "a:tblPr");
|
|
5412
|
+
const fill = tblPr && firstChild(tblPr, "a:solidFill");
|
|
5413
|
+
const scheme = fill && firstChild(fill, "a:schemeClr");
|
|
5414
|
+
return scheme ? attr(scheme, "val") : null;
|
|
5415
|
+
}
|
|
4896
5416
|
/** Whether the first row is styled as a header (`a:tblPr/@firstRow`). */
|
|
4897
5417
|
get firstRowHeader() {
|
|
4898
5418
|
return this.#tblPrFlag("firstRow");
|
|
@@ -4909,6 +5429,83 @@ var Table = class {
|
|
|
4909
5429
|
cell(rowIndex, columnIndex) {
|
|
4910
5430
|
return this.rows[rowIndex]?.cells[columnIndex] ?? null;
|
|
4911
5431
|
}
|
|
5432
|
+
/**
|
|
5433
|
+
* Insert a row, defaulting to the bottom of the table. Returns the new {@link TableRow}.
|
|
5434
|
+
*
|
|
5435
|
+
* The new row is auto-height (`a:tr/@h="0"`) and its cells are empty. Inserting *through*
|
|
5436
|
+
* a vertical merge extends that merge rather than interrupting it: the span's origin
|
|
5437
|
+
* grows by a row and the new cell joins as a continuation, because an origin claiming
|
|
5438
|
+
* more rows than it has continuations is a table PowerPoint reports as corrupt.
|
|
5439
|
+
* @param {number} [index] - where to insert, `0`..`rowCount`; appended when omitted
|
|
5440
|
+
* @throws {InvalidOptionError} when `index` is outside that range
|
|
5441
|
+
*/
|
|
5442
|
+
addRow(index) {
|
|
5443
|
+
const tr = insertRow(this.tbl, index);
|
|
5444
|
+
this.part.markDirty();
|
|
5445
|
+
return new TableRow(tr, this.part, this.themeColors, this.#styleContext(), rowsOf(this.tbl).indexOf(tr), this.rels);
|
|
5446
|
+
}
|
|
5447
|
+
/**
|
|
5448
|
+
* Remove the row at `index`, with its content.
|
|
5449
|
+
*
|
|
5450
|
+
* A cell in the row that *continues* a vertical merge shortens that merge. A cell that
|
|
5451
|
+
* *starts* one hands the region to its first continuation, which becomes the new origin —
|
|
5452
|
+
* the merged region survives one row shorter, and only the removed row's own text is lost.
|
|
5453
|
+
* @throws {InvalidOptionError} when `index` is out of range
|
|
5454
|
+
*/
|
|
5455
|
+
removeRow(index) {
|
|
5456
|
+
removeRow(this.tbl, index);
|
|
5457
|
+
this.part.markDirty();
|
|
5458
|
+
}
|
|
5459
|
+
/**
|
|
5460
|
+
* Insert a column, defaulting to the right-hand end. Updates `a:tblGrid` **and** every
|
|
5461
|
+
* row, which is the pair that has to stay in step.
|
|
5462
|
+
*
|
|
5463
|
+
* The mirror of {@link addRow}'s merge case: inserting inside a horizontal merge widens
|
|
5464
|
+
* it instead of splitting it.
|
|
5465
|
+
* @param {number} [index] - where to insert, `0`..`columnCount`; appended when omitted
|
|
5466
|
+
* @param {number} [widthEmu] - the new column's width; defaults to 1 inch
|
|
5467
|
+
* @throws {InvalidOptionError} when `index` is outside that range
|
|
5468
|
+
*/
|
|
5469
|
+
addColumn(index, widthEmu) {
|
|
5470
|
+
insertColumn(this.tbl, index, widthEmu);
|
|
5471
|
+
this.part.markDirty();
|
|
5472
|
+
}
|
|
5473
|
+
/**
|
|
5474
|
+
* Remove the column at `index`, from `a:tblGrid` and from every row.
|
|
5475
|
+
*
|
|
5476
|
+
* Inside a horizontal merge the region narrows by one and keeps its content: a covered
|
|
5477
|
+
* cell is dropped rather than the origin. Elsewhere the column's cells go with it.
|
|
5478
|
+
* @throws {InvalidOptionError} when `index` is out of range
|
|
5479
|
+
*/
|
|
5480
|
+
removeColumn(index) {
|
|
5481
|
+
removeColumn(this.tbl, index);
|
|
5482
|
+
this.part.markDirty();
|
|
5483
|
+
}
|
|
5484
|
+
/**
|
|
5485
|
+
* Merge the rectangle between two cell positions into one cell. The top-left cell keeps
|
|
5486
|
+
* its content; the rest become covered cells and are emptied, since a covered cell is
|
|
5487
|
+
* never rendered.
|
|
5488
|
+
*
|
|
5489
|
+
* A rectangle that cuts through an existing merge is **rejected**, not silently widened
|
|
5490
|
+
* to fit — the caller asked for a specific region, and quietly producing a different one
|
|
5491
|
+
* is how a layout ends up wrong with nothing to point at. Unmerge first.
|
|
5492
|
+
* @throws {InvalidOptionError} when an index is out of range, the range covers one cell,
|
|
5493
|
+
* or it partially overlaps an existing merge
|
|
5494
|
+
*/
|
|
5495
|
+
mergeCells(row1, col1, row2, col2) {
|
|
5496
|
+
mergeCells(this.tbl, row1, col1, row2, col2);
|
|
5497
|
+
this.part.markDirty();
|
|
5498
|
+
}
|
|
5499
|
+
/**
|
|
5500
|
+
* Split the merged cell whose **origin** is `(row, col)` back into individual cells.
|
|
5501
|
+
* A no-op on a cell that is not merged; addressing a covered cell instead of the origin
|
|
5502
|
+
* throws, and the message names the origin to use.
|
|
5503
|
+
* @throws {InvalidOptionError} when an index is out of range or the cell is a covered cell
|
|
5504
|
+
*/
|
|
5505
|
+
unmergeCell(row, col) {
|
|
5506
|
+
unmergeCell(this.tbl, row, col);
|
|
5507
|
+
this.part.markDirty();
|
|
5508
|
+
}
|
|
4912
5509
|
/** Escape hatch: the underlying `a:tbl` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
|
|
4913
5510
|
get element_() {
|
|
4914
5511
|
return this.tbl;
|
|
@@ -4999,6 +5596,183 @@ var TableCell = class {
|
|
|
4999
5596
|
return firstChild(this.tc, "a:tcPr");
|
|
5000
5597
|
}
|
|
5001
5598
|
/**
|
|
5599
|
+
* The cell's `a:tcPr`, creating it when absent.
|
|
5600
|
+
*
|
|
5601
|
+
* `CT_TableCell` sequences `a:txBody` then `a:tcPr` then `a:extLst`, so a newly created
|
|
5602
|
+
* one is inserted before `a:extLst` — appending it blindly would put it after and make
|
|
5603
|
+
* the part invalid. Every setter below goes through here for that reason.
|
|
5604
|
+
*/
|
|
5605
|
+
#getOrAddTcPr() {
|
|
5606
|
+
return getOrAddChild(this.tc, "a:tcPr", ["a:extLst"]);
|
|
5607
|
+
}
|
|
5608
|
+
/**
|
|
5609
|
+
* Set (or clear) the cell's vertical text anchor (`a:tcPr/@anchor`).
|
|
5610
|
+
* `null` removes the attribute, leaving PowerPoint's default of top.
|
|
5611
|
+
* @throws {InvalidOptionError} when the value is outside `ST_TextAnchoringType`
|
|
5612
|
+
*/
|
|
5613
|
+
setAnchor(value) {
|
|
5614
|
+
this.#setTcPrAttr("anchor", value, ANCHOR_VALUES, "table/invalid-cell-anchor");
|
|
5615
|
+
}
|
|
5616
|
+
/**
|
|
5617
|
+
* Set (or clear) the cell's text direction (`a:tcPr/@vert`), e.g. `'vert270'`.
|
|
5618
|
+
* `null` removes the attribute, leaving the default horizontal text.
|
|
5619
|
+
* @throws {InvalidOptionError} when the value is outside `ST_TextVerticalType`
|
|
5620
|
+
*/
|
|
5621
|
+
setVerticalText(value) {
|
|
5622
|
+
this.#setTcPrAttr("vert", value, VERT_VALUES, "table/invalid-cell-vert");
|
|
5623
|
+
}
|
|
5624
|
+
/**
|
|
5625
|
+
* Set (or clear) `a:tcPr/@horzOverflow` — what a single glyph too wide for the cell does.
|
|
5626
|
+
* `null` removes the attribute; so does `'clip'` in effect, since it is the schema
|
|
5627
|
+
* default, but the attribute is still written as asked.
|
|
5628
|
+
* @throws {InvalidOptionError} when the value is outside `ST_TextHorzOverflowType`
|
|
5629
|
+
*/
|
|
5630
|
+
setHorzOverflow(value) {
|
|
5631
|
+
this.#setTcPrAttr("horzOverflow", value, HORZ_OVERFLOW_VALUES, "table/invalid-cell-overflow");
|
|
5632
|
+
}
|
|
5633
|
+
/**
|
|
5634
|
+
* Centre the cell's text block horizontally, or stop doing so (`a:tcPr/@anchorCtr`).
|
|
5635
|
+
* `false` removes the attribute rather than writing `"0"`, since `false` is the schema
|
|
5636
|
+
* default and the two are indistinguishable to a renderer.
|
|
5637
|
+
*/
|
|
5638
|
+
setAnchorCtr(value) {
|
|
5639
|
+
const tcPr = this.#getOrAddTcPr();
|
|
5640
|
+
if (value) setAttr(tcPr, "anchorCtr", "1");
|
|
5641
|
+
else removeAttr(tcPr, "anchorCtr");
|
|
5642
|
+
this.part.markDirty();
|
|
5643
|
+
}
|
|
5644
|
+
/**
|
|
5645
|
+
* Set the cell's text insets in EMU (`a:tcPr/@marL`/`@marR`/`@marT`/`@marB`).
|
|
5646
|
+
*
|
|
5647
|
+
* Partial: only the sides named are touched, so `{ left: 0 }` flushes the text left and
|
|
5648
|
+
* leaves the other three alone. A side given as `null` has its attribute removed, which
|
|
5649
|
+
* returns it to the schema default (91440 EMU left/right, 45720 top/bottom) — not to
|
|
5650
|
+
* zero. Pass `{}` to change nothing.
|
|
5651
|
+
* @throws {InvalidOptionError} when a value is not a finite number
|
|
5652
|
+
*/
|
|
5653
|
+
setMarginsEmu(margins) {
|
|
5654
|
+
const tcPr = this.#getOrAddTcPr();
|
|
5655
|
+
const sides = [
|
|
5656
|
+
["marL", margins.left],
|
|
5657
|
+
["marR", margins.right],
|
|
5658
|
+
["marT", margins.top],
|
|
5659
|
+
["marB", margins.bottom]
|
|
5660
|
+
];
|
|
5661
|
+
for (const [name, value] of sides) {
|
|
5662
|
+
if (value === void 0) continue;
|
|
5663
|
+
if (value === null) removeAttr(tcPr, name);
|
|
5664
|
+
else setAttr(tcPr, name, String(checkFiniteEmu(value, name, "table/invalid-cell-margin")));
|
|
5665
|
+
}
|
|
5666
|
+
this.part.markDirty();
|
|
5667
|
+
}
|
|
5668
|
+
/**
|
|
5669
|
+
* Set (or clear) one of the cell's six borders — the four edges and the two diagonals.
|
|
5670
|
+
*
|
|
5671
|
+
* `null` removes the element entirely, which is "inherit", and is a different thing from
|
|
5672
|
+
* `{ noFill: true }`, which writes an explicit no-border and suppresses whatever would
|
|
5673
|
+
* otherwise be inherited. The element is inserted at its schema position rather than
|
|
5674
|
+
* appended: `CT_TableCellProperties` is a sequence, and an out-of-order `a:tcPr` is
|
|
5675
|
+
* reported by PowerPoint as a corrupt file rather than as a bad edit.
|
|
5676
|
+
*
|
|
5677
|
+
* Colour is either `color` (6-hex, `#` optional) or `schemeColor` (a theme token); giving
|
|
5678
|
+
* both prefers the token, matching how the read side reports them.
|
|
5679
|
+
* @throws {InvalidOptionError} when the width or colour cannot be written
|
|
5680
|
+
*/
|
|
5681
|
+
setBorder(edge, border) {
|
|
5682
|
+
const qname = EDGE_QNAMES[edge];
|
|
5683
|
+
if (!qname) throw new InvalidOptionError("table/invalid-cell-border", `Unknown table cell edge: ${JSON.stringify(edge)}. Expected one of: ${Object.keys(EDGE_QNAMES).join(", ")}.`);
|
|
5684
|
+
if (border === null) {
|
|
5685
|
+
const tcPr = this.#tcPr();
|
|
5686
|
+
if (!tcPr || !firstChild(tcPr, qname)) return;
|
|
5687
|
+
removeChildrenByQName(tcPr, [qname]);
|
|
5688
|
+
this.part.markDirty();
|
|
5689
|
+
return;
|
|
5690
|
+
}
|
|
5691
|
+
const tcPr = this.#getOrAddTcPr();
|
|
5692
|
+
removeChildrenByQName(tcPr, [qname]);
|
|
5693
|
+
const doc = ownerDocumentOf(tcPr);
|
|
5694
|
+
const ln = createElement(doc, qname);
|
|
5695
|
+
if (border.widthPt !== void 0 && border.widthPt !== null) setAttr(ln, "w", String(checkFiniteEmu(border.widthPt * 12700, "widthPt", "table/invalid-cell-border")));
|
|
5696
|
+
if (border.noFill) ln.appendChild(createElement(doc, "a:noFill"));
|
|
5697
|
+
else if (border.schemeColor || border.color) {
|
|
5698
|
+
const fill = createElement(doc, "a:solidFill");
|
|
5699
|
+
const scheme = border.schemeColor;
|
|
5700
|
+
const clr = createElement(doc, scheme ? "a:schemeClr" : "a:srgbClr");
|
|
5701
|
+
setAttr(clr, "val", scheme ? scheme : normalizeHex(border.color));
|
|
5702
|
+
fill.appendChild(clr);
|
|
5703
|
+
ln.appendChild(fill);
|
|
5704
|
+
}
|
|
5705
|
+
if (border.dash) {
|
|
5706
|
+
const dash = createElement(doc, "a:prstDash");
|
|
5707
|
+
setAttr(dash, "val", border.dash);
|
|
5708
|
+
ln.appendChild(dash);
|
|
5709
|
+
}
|
|
5710
|
+
insertTcPrChild(tcPr, qname, ln);
|
|
5711
|
+
this.part.markDirty();
|
|
5712
|
+
}
|
|
5713
|
+
/**
|
|
5714
|
+
* Replace the cell's fill with a solid colour (`a:tcPr/a:solidFill`), or clear it.
|
|
5715
|
+
*
|
|
5716
|
+
* `null` removes the `a:solidFill` and lets the cell inherit from the table style again.
|
|
5717
|
+
* That is not the same as {@link noFill}, which writes an explicit `a:noFill` and so
|
|
5718
|
+
* suppresses the inherited shading. Any competing fill choice (`a:gradFill`,
|
|
5719
|
+
* `a:blipFill`, …) is dropped first — `EG_FillProperties` admits one.
|
|
5720
|
+
* @throws {InvalidOptionError} when `color` is not a 6-digit hex string
|
|
5721
|
+
*/
|
|
5722
|
+
setFillColor(color) {
|
|
5723
|
+
this.#setFill(color === null ? null : {
|
|
5724
|
+
qname: "a:srgbClr",
|
|
5725
|
+
val: normalizeHex(color)
|
|
5726
|
+
});
|
|
5727
|
+
}
|
|
5728
|
+
/**
|
|
5729
|
+
* Replace the cell's fill with a theme colour token (`a:solidFill/a:schemeClr/@val`), or
|
|
5730
|
+
* clear it. Preferred over {@link setFillColor} when the deck's theme should keep
|
|
5731
|
+
* driving the colour.
|
|
5732
|
+
*/
|
|
5733
|
+
setFillSchemeColor(token) {
|
|
5734
|
+
this.#setFill(token === null ? null : {
|
|
5735
|
+
qname: "a:schemeClr",
|
|
5736
|
+
val: token
|
|
5737
|
+
});
|
|
5738
|
+
}
|
|
5739
|
+
/**
|
|
5740
|
+
* Write an explicit `<a:noFill/>` on the cell — a transparent cell that shows the table
|
|
5741
|
+
* background (or the slide) through. Distinct from `setFillColor(null)`, which removes
|
|
5742
|
+
* the fill and lets the table style's shading apply again.
|
|
5743
|
+
*/
|
|
5744
|
+
noFill() {
|
|
5745
|
+
const tcPr = this.#getOrAddTcPr();
|
|
5746
|
+
removeChildrenByQName(tcPr, FILL_CHOICES);
|
|
5747
|
+
tcPrChild(tcPr, "a:noFill");
|
|
5748
|
+
this.part.markDirty();
|
|
5749
|
+
}
|
|
5750
|
+
/** Set or clear one `a:tcPr` attribute, vetting it against its schema enum first. */
|
|
5751
|
+
#setTcPrAttr(name, value, valid, code) {
|
|
5752
|
+
if (value === null) {
|
|
5753
|
+
const tcPr = this.#tcPr();
|
|
5754
|
+
if (!tcPr) return;
|
|
5755
|
+
removeAttr(tcPr, name);
|
|
5756
|
+
this.part.markDirty();
|
|
5757
|
+
return;
|
|
5758
|
+
}
|
|
5759
|
+
const checked = checkEnum(value, valid, name, code);
|
|
5760
|
+
setAttr(this.#getOrAddTcPr(), name, checked);
|
|
5761
|
+
this.part.markDirty();
|
|
5762
|
+
}
|
|
5763
|
+
/** Replace (or remove) the cell's solid fill, keeping `EG_FillProperties` single-valued. */
|
|
5764
|
+
#setFill(color) {
|
|
5765
|
+
if (color === null) {
|
|
5766
|
+
const tcPr = this.#tcPr();
|
|
5767
|
+
if (!tcPr || !firstChild(tcPr, "a:solidFill")) return;
|
|
5768
|
+
removeChildrenByQName(tcPr, ["a:solidFill"]);
|
|
5769
|
+
this.part.markDirty();
|
|
5770
|
+
return;
|
|
5771
|
+
}
|
|
5772
|
+
setSolidFill(this.#getOrAddTcPr(), TCPR_AFTER["a:solidFill"] ?? [], color);
|
|
5773
|
+
this.part.markDirty();
|
|
5774
|
+
}
|
|
5775
|
+
/**
|
|
5002
5776
|
* The cell's solid fill resolved against the table's theme colour context to a
|
|
5003
5777
|
* literal hex — the table-cell counterpart of
|
|
5004
5778
|
* {@link import('./shapes.js').AutoShape.resolvedFill}. The cell's own
|
|
@@ -5020,11 +5794,25 @@ var TableCell = class {
|
|
|
5020
5794
|
*/
|
|
5021
5795
|
get resolvedFill() {
|
|
5022
5796
|
if (!this.themeColors) return null;
|
|
5023
|
-
|
|
5024
|
-
if (tcPr && FILL_CHOICES.some((q) => firstChild(tcPr, q))) return resolveSolidFillColor(tcPr, this.themeColors);
|
|
5797
|
+
if (this.hasOwnFill) return resolveSolidFillColor(this.#tcPr(), this.themeColors);
|
|
5025
5798
|
return this.style ? this.#styleFill() : null;
|
|
5026
5799
|
}
|
|
5027
5800
|
/**
|
|
5801
|
+
* Whether the cell carries a fill of its **own** (`a:tcPr` holds an `EG_FillProperties`
|
|
5802
|
+
* child), as opposed to inheriting one from the table style's header/banding rules.
|
|
5803
|
+
*
|
|
5804
|
+
* This is the flag that disambiguates {@link resolvedFill}, which deliberately reports
|
|
5805
|
+
* either — it answers "what colour does this cell render as", and both sources are valid
|
|
5806
|
+
* answers to that. Anything that has to reproduce the cell rather than describe it needs
|
|
5807
|
+
* to know which: baking an inherited banding colour into a copy makes the copy look right
|
|
5808
|
+
* until someone changes its table style, and then nothing moves. `false` for a cell whose
|
|
5809
|
+
* `a:tcPr` is empty or absent, whatever the style graph would render it as.
|
|
5810
|
+
*/
|
|
5811
|
+
get hasOwnFill() {
|
|
5812
|
+
const tcPr = this.#tcPr();
|
|
5813
|
+
return !!tcPr && FILL_CHOICES.some((q) => firstChild(tcPr, q));
|
|
5814
|
+
}
|
|
5815
|
+
/**
|
|
5028
5816
|
* The cell's picture (image) fill (`a:tcPr/a:blipFill`), or `null` when the cell
|
|
5029
5817
|
* is not image-filled. The cell counterpart of
|
|
5030
5818
|
* {@link import('./shapes.js').AutoShape.pictureFill}: {@link resolvedFill}
|
|
@@ -5045,6 +5833,24 @@ var TableCell = class {
|
|
|
5045
5833
|
return resolveTableCellStyleFill(s.style.element_, s.flags, this.rowIndex, this.colIndex, s.rowCount, s.colCount, s.ctx);
|
|
5046
5834
|
}
|
|
5047
5835
|
/**
|
|
5836
|
+
* The cell's gradient fill (`a:tcPr/a:gradFill`), or `null` when the cell is not
|
|
5837
|
+
* gradient-filled. The cell twin of {@link Table.gradientFill}, and needed for the same
|
|
5838
|
+
* reason {@link pictureFill} is: {@link resolvedFill} reports `null` for every non-solid
|
|
5839
|
+
* choice, so without this a gradient cell is indistinguishable from an unfilled one.
|
|
5840
|
+
*/
|
|
5841
|
+
get gradientFill() {
|
|
5842
|
+
const tcPr = this.#tcPr();
|
|
5843
|
+
return tcPr && this.themeColors ? readGradientFill(tcPr, this.themeColors) : null;
|
|
5844
|
+
}
|
|
5845
|
+
/**
|
|
5846
|
+
* The cell's pattern (hatch) fill (`a:tcPr/a:pattFill`), or `null` when the cell is not
|
|
5847
|
+
* pattern-filled.
|
|
5848
|
+
*/
|
|
5849
|
+
get patternFill() {
|
|
5850
|
+
const tcPr = this.#tcPr();
|
|
5851
|
+
return tcPr && this.themeColors ? readPatternFill(tcPr, this.themeColors) : null;
|
|
5852
|
+
}
|
|
5853
|
+
/**
|
|
5048
5854
|
* The raw `schemeClr` token of the cell's solid fill (`a:tcPr/a:solidFill/a:schemeClr/@val`),
|
|
5049
5855
|
* e.g. `accent1`/`bg1`, or `null` when the fill is absent or an explicit `srgbClr`.
|
|
5050
5856
|
* The resolved literal is {@link resolvedFill}; this is the unresolved reference.
|
|
@@ -5111,6 +5917,88 @@ var TableCell = class {
|
|
|
5111
5917
|
return (tcPr && attr(tcPr, "anchor")) ?? null;
|
|
5112
5918
|
}
|
|
5113
5919
|
/**
|
|
5920
|
+
* Whether the cell's whole text **block** is centred horizontally within it
|
|
5921
|
+
* (`a:tcPr/@anchorCtr`). `false` when unset — that is the schema default, and it is
|
|
5922
|
+
* what PowerPoint writes nothing for.
|
|
5923
|
+
*
|
|
5924
|
+
* Distinct from a paragraph's `align`, which decides where each *line* sits inside the
|
|
5925
|
+
* text block; this decides where the block sits inside the cell.
|
|
5926
|
+
*/
|
|
5927
|
+
get anchorCtr() {
|
|
5928
|
+
const tcPr = this.#tcPr();
|
|
5929
|
+
return tcPr ? attr(tcPr, "anchorCtr") === "1" || attr(tcPr, "anchorCtr") === "true" : false;
|
|
5930
|
+
}
|
|
5931
|
+
/**
|
|
5932
|
+
* The cell's 3-D bevel (`a:tcPr/a:cell3D`), or `null` when it has none.
|
|
5933
|
+
*
|
|
5934
|
+
* `CT_Cell3D` requires an `a:bevel`, so a present `cell3D` always reports a bevel;
|
|
5935
|
+
* `lightRig` is `null` when the cell leaves the scene lighting to the renderer. Sizes are
|
|
5936
|
+
* reported in **points** (the attributes are EMU), matching how the write option takes them.
|
|
5937
|
+
*/
|
|
5938
|
+
get cell3D() {
|
|
5939
|
+
const tcPr = this.#tcPr();
|
|
5940
|
+
const cell3D = tcPr && firstChild(tcPr, "a:cell3D");
|
|
5941
|
+
if (!cell3D) return null;
|
|
5942
|
+
const bevel = firstChild(cell3D, "a:bevel");
|
|
5943
|
+
const rig = firstChild(cell3D, "a:lightRig");
|
|
5944
|
+
const pts = (value) => {
|
|
5945
|
+
const emu = intValue(value);
|
|
5946
|
+
return emu === null ? null : emu / 12700;
|
|
5947
|
+
};
|
|
5948
|
+
return {
|
|
5949
|
+
material: attr(cell3D, "prstMaterial") ?? null,
|
|
5950
|
+
bevel: {
|
|
5951
|
+
preset: bevel ? attr(bevel, "prst") ?? null : null,
|
|
5952
|
+
widthPt: bevel ? pts(attr(bevel, "w")) : null,
|
|
5953
|
+
heightPt: bevel ? pts(attr(bevel, "h")) : null
|
|
5954
|
+
},
|
|
5955
|
+
lightRig: rig ? {
|
|
5956
|
+
rig: attr(rig, "rig") ?? null,
|
|
5957
|
+
dir: attr(rig, "dir") ?? null
|
|
5958
|
+
} : null
|
|
5959
|
+
};
|
|
5960
|
+
}
|
|
5961
|
+
/**
|
|
5962
|
+
* The cell's unique identifier (`a:tc/@id`), or `null` when it has none.
|
|
5963
|
+
*
|
|
5964
|
+
* This is what {@link headerIds} references: a data cell names the header cells that
|
|
5965
|
+
* govern it by their `@id`, which is how a complex table tells a screen reader what a
|
|
5966
|
+
* value means. Unrelated to the shape-level `p:cNvPr/@id` — it is an `xs:string` scoped
|
|
5967
|
+
* to the table, not a slide-wide numeric id.
|
|
5968
|
+
*
|
|
5969
|
+
* **PowerPoint does not write this and strips it on save**, so it will read `null` on
|
|
5970
|
+
* any deck PowerPoint has saved, however it was produced. It is surfaced for decks from
|
|
5971
|
+
* other producers. There is deliberately no write-API counterpart — see
|
|
5972
|
+
* `test/read/fixtures/authoring/probe-table-cell-a11y-and-3d.ps1` for the measurement.
|
|
5973
|
+
*/
|
|
5974
|
+
get id() {
|
|
5975
|
+
return attr(this.tc, "id") ?? null;
|
|
5976
|
+
}
|
|
5977
|
+
/**
|
|
5978
|
+
* The `@id`s of the header cells that govern this cell
|
|
5979
|
+
* (`a:tcPr/a:headers/a:header/@val`), in document order. Empty when the cell declares no
|
|
5980
|
+
* header association — which is the common case, since only a complex table needs one.
|
|
5981
|
+
*
|
|
5982
|
+
* Carries the same caveat as {@link id}: PowerPoint strips `a:headers` on save, so this
|
|
5983
|
+
* is empty on any PowerPoint-saved deck. `Table.firstRowHeader` (`a:tblPr/@firstRow`) is
|
|
5984
|
+
* the header marker PowerPoint does keep.
|
|
5985
|
+
*/
|
|
5986
|
+
get headerIds() {
|
|
5987
|
+
const tcPr = this.#tcPr();
|
|
5988
|
+
const headers = tcPr && firstChild(tcPr, "a:headers");
|
|
5989
|
+
if (!headers) return [];
|
|
5990
|
+
return getElements(headers, "a:header").map((header) => attr(header, "val")).filter((val) => val !== null && val !== "");
|
|
5991
|
+
}
|
|
5992
|
+
/**
|
|
5993
|
+
* How the cell treats a glyph too wide for its text width (`a:tcPr/@horzOverflow`):
|
|
5994
|
+
* `'clip'` cuts it at the cell edge, `'overflow'` lets it draw past. `null` when unset
|
|
5995
|
+
* (PowerPoint clips). Not a wrap flag — cell text always wraps to the column width.
|
|
5996
|
+
*/
|
|
5997
|
+
get horzOverflow() {
|
|
5998
|
+
const tcPr = this.#tcPr();
|
|
5999
|
+
return (tcPr && attr(tcPr, "horzOverflow")) ?? null;
|
|
6000
|
+
}
|
|
6001
|
+
/**
|
|
5114
6002
|
* The cell's text insets in EMU (`a:tcPr/@marL`/`@marR`/`@marT`/`@marB`), or
|
|
5115
6003
|
* `null` when the cell sets none. Each side is `null` when only some are set.
|
|
5116
6004
|
*/
|
|
@@ -5360,6 +6248,6 @@ function buildShapes(parent, slide) {
|
|
|
5360
6248
|
return shapes;
|
|
5361
6249
|
}
|
|
5362
6250
|
//#endregion
|
|
5363
|
-
export {
|
|
6251
|
+
export { createElement as $, resolveLayoutColorContext as A, remapLiteralColors as B, Paragraph as C, readPictureFill as D, readPatternFill as E, applyColorTransforms as F, relativePartName as G, styleRefFill as H, flattenShape as I, zipPathToPartName as J, relsPartNameFor as K, flattenSlide as L, resolveNotesColorContext as M, resolveSlideColorContext as N, readGradientFill as O, resolveSlideThemeParts as P, childElements$2 as Q, parseClrMap as R, Shape as S, TextFrame as T, partNameExtension as U, restyleSlide as V, partNameToZipPath as W, attr as X, OOXML_NS as Y, boolValue as Z, ChartAxis as _, isGraphicFrame as a, insertInOrder as at, Picture as b, wrapShapeElement as c, parseXml as ct, TableCell as d, serializeXml as dt, escapeXmlAttribute as et, TableRow as f, setAttr as ft, Chart as g, ChartExSeries as h, isConnector as i, getOrAddChild as it, resolveMasterColorContext as j, resolveColorElement as k, GraphicFrame as l, removeAttr as lt, ChartExAxis as m, buildShapes as n, firstChildElement as nt, isGroupShape as o, intValue as ot, ChartEx as p, resolveRelativePartName as q, isAutoShape as r, getElements as rt, isPicture as s, ownerDocumentOf as st, GroupShape as t, firstChild as tt, Table as u, removeChildrenByQName as ut, ChartSeries as v, Run as w, AutoShape as x, Connector as y, parseClrScheme as z };
|
|
5364
6252
|
|
|
5365
|
-
//# sourceMappingURL=shapes-
|
|
6253
|
+
//# sourceMappingURL=shapes-CaOgR0i1.js.map
|