@rowsncolumns/toolkit 24.4.5 → 24.5.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/dist/cjs/autofilter-condition.d.ts +45 -1
- package/dist/cjs/autofilter-condition.d.ts.map +1 -1
- package/dist/cjs/autofilter-condition.js +135 -12
- package/dist/cjs/excel-parser/helpers.d.ts +15 -1
- package/dist/cjs/excel-parser/helpers.d.ts.map +1 -1
- package/dist/cjs/excel-parser/helpers.js +119 -5
- package/dist/cjs/excel-parser/interface.d.ts +3 -1
- package/dist/cjs/excel-parser/interface.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/ods/index.js +186 -97
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts +15 -0
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/ods/styles.js +80 -6
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsb/index.js +107 -103
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts +77 -1
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/charts.js +920 -122
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts +7 -1
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.js +24 -9
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts +24 -3
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.js +25 -3
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts +24 -1
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/index.js +561 -394
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts +8 -2
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.js +312 -21
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.d.ts +6 -0
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.js +9 -0
- package/dist/cjs/excel-parser/plugins/xlsx/theme.d.ts +1 -1
- package/dist/cjs/excel-parser/types.d.ts +9 -1
- package/dist/cjs/excel-parser/types.d.ts.map +1 -1
- package/dist/cjs/excel-parser/workbook.d.ts +1 -0
- package/dist/cjs/excel-parser/workbook.d.ts.map +1 -1
- package/dist/cjs/excel-parser/workbook.js +5 -0
- package/dist/cjs/excel-parser/worker.js +2 -0
- package/dist/cjs/exporter/ods/ods-export.d.ts.map +1 -1
- package/dist/cjs/exporter/ods/ods-export.js +255 -80
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts +7 -1
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/chart-builder.js +902 -119
- package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts +16 -3
- package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/form-controls-builder.js +30 -8
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/pivot-builder.js +206 -162
- package/dist/cjs/exporter/xlsx/style-builder.d.ts +8 -2
- package/dist/cjs/exporter/xlsx/style-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/style-builder.js +25 -0
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts +2 -2
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/xlsx-export.js +728 -452
- package/dist/esm/autofilter-condition.d.ts +45 -1
- package/dist/esm/autofilter-condition.d.ts.map +1 -1
- package/dist/esm/autofilter-condition.js +131 -11
- package/dist/esm/excel-parser/helpers.d.ts +15 -1
- package/dist/esm/excel-parser/helpers.d.ts.map +1 -1
- package/dist/esm/excel-parser/helpers.js +94 -4
- package/dist/esm/excel-parser/interface.d.ts +3 -1
- package/dist/esm/excel-parser/interface.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/ods/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/ods/index.js +105 -22
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts +15 -0
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/ods/styles.js +79 -5
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsb/index.js +15 -7
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts +77 -1
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/charts.js +708 -16
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts +7 -1
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/drawing.js +23 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts +24 -3
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.js +21 -3
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts +24 -1
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/index.js +192 -54
- package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts +8 -2
- package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/pivots.js +220 -4
- package/dist/esm/excel-parser/plugins/xlsx/relationships.d.ts +6 -0
- package/dist/esm/excel-parser/plugins/xlsx/relationships.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/relationships.js +9 -0
- package/dist/esm/excel-parser/plugins/xlsx/theme.d.ts +1 -1
- package/dist/esm/excel-parser/types.d.ts +9 -1
- package/dist/esm/excel-parser/types.d.ts.map +1 -1
- package/dist/esm/excel-parser/workbook.d.ts +1 -0
- package/dist/esm/excel-parser/workbook.d.ts.map +1 -1
- package/dist/esm/excel-parser/workbook.js +4 -0
- package/dist/esm/excel-parser/worker.js +2 -0
- package/dist/esm/exporter/ods/ods-export.d.ts.map +1 -1
- package/dist/esm/exporter/ods/ods-export.js +238 -72
- package/dist/esm/exporter/xlsx/chart-builder.d.ts +7 -1
- package/dist/esm/exporter/xlsx/chart-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/chart-builder.js +674 -58
- package/dist/esm/exporter/xlsx/form-controls-builder.d.ts +16 -3
- package/dist/esm/exporter/xlsx/form-controls-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/form-controls-builder.js +29 -8
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/pivot-builder.js +187 -139
- package/dist/esm/exporter/xlsx/style-builder.d.ts +8 -2
- package/dist/esm/exporter/xlsx/style-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/style-builder.js +28 -0
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts +2 -2
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/xlsx-export.js +451 -197
- package/package.json +10 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EmbedFormControlSpec } from "@rowsncolumns/spreadsheet";
|
|
1
|
+
import type { EmbedFormControlSpec, OverlayPosition } from "@rowsncolumns/spreadsheet";
|
|
2
2
|
/**
|
|
3
3
|
* Excel form-control writers — the inverse of
|
|
4
4
|
* `excel-parser/plugins/xlsx/form-controls.ts`. A control is three parts:
|
|
@@ -20,13 +20,25 @@ export type ControlCellAnchor = {
|
|
|
20
20
|
row: number;
|
|
21
21
|
rowOff: number;
|
|
22
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* The `<anchor moveWithCells sizeWithCells>` flags to write: the control's
|
|
25
|
+
* placement mode when its position carries one (Move and size = both, Move
|
|
26
|
+
* but don't size = `moveWithCells`, Don't move or size = neither) — a
|
|
27
|
+
* persisted second anchor is a "Move and size" object too — else the flags
|
|
28
|
+
* the spec arrived with (#668 C-46).
|
|
29
|
+
*/
|
|
30
|
+
export declare const controlAnchorFlags: (spec: Pick<EmbedFormControlSpec, "moveWithCells" | "sizeWithCells">, overlay?: Pick<OverlayPosition, "placement" | "toCell"> | null) => {
|
|
31
|
+
moveWithCells: boolean;
|
|
32
|
+
sizeWithCells: boolean;
|
|
33
|
+
};
|
|
23
34
|
/** One `<control>` element (inside the `<controls>` wrapper). */
|
|
24
|
-
export declare const buildControlElementXml: ({ spec, relId, shapeId, from, to, }: {
|
|
35
|
+
export declare const buildControlElementXml: ({ spec, relId, shapeId, from, to, overlay, }: {
|
|
25
36
|
spec: EmbedFormControlSpec;
|
|
26
37
|
relId: string;
|
|
27
38
|
shapeId: number;
|
|
28
39
|
from: ControlCellAnchor;
|
|
29
40
|
to: ControlCellAnchor;
|
|
41
|
+
overlay?: Pick<OverlayPosition, "placement" | "toCell"> | null;
|
|
30
42
|
}) => string;
|
|
31
43
|
/**
|
|
32
44
|
* The worksheet `<controls>` element. Excel wraps controls in an
|
|
@@ -47,11 +59,12 @@ export type FormControlVmlGeometry = {
|
|
|
47
59
|
anchor: [number, number, number, number, number, number, number, number];
|
|
48
60
|
};
|
|
49
61
|
/** One `<v:shape>` drawing a form control. */
|
|
50
|
-
export declare const buildFormControlVmlShape: ({ spec, shapeId, zIndex, geometry, }: {
|
|
62
|
+
export declare const buildFormControlVmlShape: ({ spec, shapeId, zIndex, geometry, overlay, }: {
|
|
51
63
|
spec: EmbedFormControlSpec;
|
|
52
64
|
shapeId: number;
|
|
53
65
|
zIndex: number;
|
|
54
66
|
geometry: FormControlVmlGeometry;
|
|
67
|
+
overlay?: Pick<OverlayPosition, "placement" | "toCell"> | null;
|
|
55
68
|
}) => string;
|
|
56
69
|
/** Wrap note + control shapes into one `vmlDrawing` part. */
|
|
57
70
|
export declare const buildVmlDrawingXml: ({ shapeTypes, shapes, }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-controls-builder.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/form-controls-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"form-controls-builder.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/form-controls-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,eAAe,EAChB,MAAM,2BAA2B,CAAC;AAEnC;;;;;;;;GAQG;AAEH,eAAO,MAAM,sBAAsB,mDACe,CAAC;AACnD,eAAO,MAAM,kBAAkB,iFACiD,CAAC;AACjF,eAAO,MAAM,eAAe,kEACqC,CAAC;AAuBlE,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,GAAI,MAAM,oBAAoB,KAAG,MAU7D,CAAC;AAEF,gEAAgE;AAChE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,IAAI,CAAC,oBAAoB,EAAE,eAAe,GAAG,eAAe,CAAC,EACnE,UAAU,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,QAAQ,CAAC,GAAG,IAAI,KAC7D;IAAE,aAAa,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAalD,CAAC;AASF,iEAAiE;AACjE,eAAO,MAAM,sBAAsB,GAAI,8CAOpC;IACD,IAAI,EAAE,oBAAoB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,iBAAiB,CAAC;IACxB,EAAE,EAAE,iBAAiB,CAAC;IACtB,OAAO,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC;CAChE,KAAG,MAcH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,iBAAiB,MAAM,EAAE,KAAG,MAK5D,CAAC;AAsEF,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,oSAA4Q,CAAC;AAEpT,iFAAiF;AACjF,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1E,CAAC;AAIF,8CAA8C;AAC9C,eAAO,MAAM,wBAAwB,GAAI,+CAMtC;IACD,IAAI,EAAE,oBAAoB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC;CAChE,KAAG,MAsBH,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,kBAAkB,GAAI,yBAGhC;IACD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,KAAG,MAAM,GAAG,SAKZ,CAAC"}
|
|
@@ -33,12 +33,33 @@ export const buildCtrlPropXml = (spec) => {
|
|
|
33
33
|
const open = `<formControlPr xmlns="${FORM_CONTROL_NS}" objectType="${escapeAttr(spec.objectType)}"${attrsXml(rest)}`;
|
|
34
34
|
return `${XML_DECLARATION}${body ? `${open}>${body}</formControlPr>` : `${open}/>`}`;
|
|
35
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* The `<anchor moveWithCells sizeWithCells>` flags to write: the control's
|
|
38
|
+
* placement mode when its position carries one (Move and size = both, Move
|
|
39
|
+
* but don't size = `moveWithCells`, Don't move or size = neither) — a
|
|
40
|
+
* persisted second anchor is a "Move and size" object too — else the flags
|
|
41
|
+
* the spec arrived with (#668 C-46).
|
|
42
|
+
*/
|
|
43
|
+
export const controlAnchorFlags = (spec, overlay) => {
|
|
44
|
+
const placement = overlay?.placement ?? (overlay?.toCell ? "moveAndSize" : undefined);
|
|
45
|
+
if (placement) {
|
|
46
|
+
return {
|
|
47
|
+
moveWithCells: placement !== "absolute",
|
|
48
|
+
sizeWithCells: placement === "moveAndSize",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
moveWithCells: spec.moveWithCells === true,
|
|
53
|
+
sizeWithCells: spec.sizeWithCells === true,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
36
56
|
const cellAnchorXml = (tag, anchor) => `<${tag}><xdr:col>${anchor.col}</xdr:col><xdr:colOff>${Math.round(anchor.colOff)}</xdr:colOff><xdr:row>${anchor.row}</xdr:row><xdr:rowOff>${Math.round(anchor.rowOff)}</xdr:rowOff></${tag}>`;
|
|
37
57
|
/** One `<control>` element (inside the `<controls>` wrapper). */
|
|
38
|
-
export const buildControlElementXml = ({ spec, relId, shapeId, from, to, }) => {
|
|
58
|
+
export const buildControlElementXml = ({ spec, relId, shapeId, from, to, overlay, }) => {
|
|
39
59
|
const name = spec.name ?? `${spec.objectType} ${shapeId}`;
|
|
40
|
-
const
|
|
41
|
-
|
|
60
|
+
const flags = controlAnchorFlags(spec, overlay);
|
|
61
|
+
const anchorAttrs = (flags.moveWithCells ? ' moveWithCells="1"' : "") +
|
|
62
|
+
(flags.sizeWithCells ? ' sizeWithCells="1"' : "");
|
|
42
63
|
return `<control shapeId="${shapeId}" r:id="${relId}" name="${escapeAttr(name)}"><controlPr${attrsXml(spec.controlProperties)}><anchor${anchorAttrs}>${cellAnchorXml("from", from)}${cellAnchorXml("to", to)}</anchor></controlPr></control>`;
|
|
43
64
|
};
|
|
44
65
|
/**
|
|
@@ -64,7 +85,7 @@ const truthy = (value) => value === "1" || value === "true";
|
|
|
64
85
|
* range, selection, scroll values) from the VML, the ctrlProp part is the
|
|
65
86
|
* x14 mirror.
|
|
66
87
|
*/
|
|
67
|
-
const clientDataChildrenXml = (spec) => {
|
|
88
|
+
const clientDataChildrenXml = (spec, flags) => {
|
|
68
89
|
const p = spec.properties ?? {};
|
|
69
90
|
const c = spec.controlProperties ?? {};
|
|
70
91
|
const out = [];
|
|
@@ -74,9 +95,9 @@ const clientDataChildrenXml = (spec) => {
|
|
|
74
95
|
else
|
|
75
96
|
out.push(`<x:${tag}>${escapeText(value)}</x:${tag}>`);
|
|
76
97
|
};
|
|
77
|
-
if (
|
|
98
|
+
if (flags.moveWithCells)
|
|
78
99
|
push("MoveWithCells");
|
|
79
|
-
if (
|
|
100
|
+
if (flags.sizeWithCells)
|
|
80
101
|
push("SizeWithCells");
|
|
81
102
|
// Anchor is inserted by the caller (needs sheet geometry).
|
|
82
103
|
out.push("__ANCHOR__");
|
|
@@ -156,12 +177,12 @@ const clientDataChildrenXml = (spec) => {
|
|
|
156
177
|
export const FORM_CONTROL_VML_SHAPETYPE = `<v:shapetype id="_x0000_t201" coordsize="21600,21600" o:spt="201" path="m,l,21600r21600,l21600,xe"><v:stroke joinstyle="miter"/><v:path shadowok="f" o:extrusionok="f" strokeok="f" fillok="f" o:connecttype="rect"/><o:lock v:ext="edit" shapetype="t"/></v:shapetype>`;
|
|
157
178
|
const toPt = (px) => `${(px * 0.75).toFixed(2).replace(/\.?0+$/, "")}pt`;
|
|
158
179
|
/** One `<v:shape>` drawing a form control. */
|
|
159
|
-
export const buildFormControlVmlShape = ({ spec, shapeId, zIndex, geometry, }) => {
|
|
180
|
+
export const buildFormControlVmlShape = ({ spec, shapeId, zIndex, geometry, overlay, }) => {
|
|
160
181
|
const objectType = VML_OBJECT_TYPE[spec.objectType] ?? spec.objectType;
|
|
161
182
|
const caption = spec.text
|
|
162
183
|
? `<div style="text-align:left"><font face="Tahoma" size="160" color="auto">${escapeText(spec.text)}</font></div>`
|
|
163
184
|
: "";
|
|
164
|
-
const clientData = clientDataChildrenXml(spec).replace("__ANCHOR__", `<x:Anchor>${geometry.anchor.join(", ")}</x:Anchor>`);
|
|
185
|
+
const clientData = clientDataChildrenXml(spec, controlAnchorFlags(spec, overlay)).replace("__ANCHOR__", `<x:Anchor>${geometry.anchor.join(", ")}</x:Anchor>`);
|
|
165
186
|
const style = `position:absolute;margin-left:${toPt(geometry.leftPx)};margin-top:${toPt(geometry.topPx)};width:${toPt(geometry.widthPx)};height:${toPt(geometry.heightPx)};z-index:${zIndex};mso-wrap-style:tight`;
|
|
166
187
|
return `<v:shape id="_x0000_s${shapeId}" type="#_x0000_t201" style="${style}" filled="f" fillcolor="window [65]" stroked="f" strokecolor="windowText [64]" o:insetmode="auto"><v:path shadowok="f" o:extrusionok="f" strokeok="f" fillok="f" o:connecttype="rect"/><v:textbox style="mso-direction-alt:auto" o:singleclick="f">${caption}</v:textbox><x:ClientData ObjectType="${escapeAttr(objectType)}">${clientData}</x:ClientData></v:shape>`;
|
|
167
188
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pivot-builder.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/pivot-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"pivot-builder.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/pivot-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAKV,UAAU,EAEX,MAAM,2BAA2B,CAAC;AAqBnC;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,GAAI,SAAS,MAAM,KAAG,MAAM,EAYjE,CAAC;AA6HF;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,GACvC,OAAO,UAAU,EACjB,WAAW,MAAM,EACjB,YAAY,MAAM,EAAE,KACnB,MAAM,GAAG,IA2CX,CAAC;AAsDF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,UAAU,EACjB,SAAS,MAAM,EACf,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAChC,MAAM,GAAG,IAkKX,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,GACjC,UAAU,MAAM,EAChB,aAAa,MAAM,KAClB,MAUF,CAAC"}
|
|
@@ -40,10 +40,26 @@ export const calculatedFieldReferences = (formula) => {
|
|
|
40
40
|
};
|
|
41
41
|
const xmlBuilder = new XMLBuilder({
|
|
42
42
|
ignoreAttributes: false,
|
|
43
|
-
|
|
43
|
+
preserveOrder: true,
|
|
44
|
+
attributeNamePrefix: "",
|
|
45
|
+
suppressEmptyNode: true,
|
|
44
46
|
format: true,
|
|
45
47
|
indentBy: " ",
|
|
46
48
|
});
|
|
49
|
+
/** An element with `attributes` (undefined values dropped) and ordered `children`. */
|
|
50
|
+
const el = (tag, attributes = {}, children = []) => {
|
|
51
|
+
const attrs = {};
|
|
52
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
53
|
+
if (value !== undefined)
|
|
54
|
+
attrs[key] = value;
|
|
55
|
+
}
|
|
56
|
+
return Object.keys(attrs).length ? { [tag]: children, ":@": attrs } : { [tag]: children };
|
|
57
|
+
};
|
|
58
|
+
const XML_DECLARATION = {
|
|
59
|
+
"?xml": [{ "#text": "" }],
|
|
60
|
+
":@": { version: "1.0", encoding: "UTF-8", standalone: "yes" },
|
|
61
|
+
};
|
|
62
|
+
const buildDocument = (root) => xmlBuilder.build([XML_DECLARATION, root]);
|
|
47
63
|
/**
|
|
48
64
|
* Convert numeric col/row to A1 notation. 1-indexed.
|
|
49
65
|
* e.g. (1, 1) → "A1", (28, 5) → "AB5".
|
|
@@ -80,6 +96,23 @@ const aggToSubtotal = (agg) => {
|
|
|
80
96
|
};
|
|
81
97
|
return map[agg] ?? "sum";
|
|
82
98
|
};
|
|
99
|
+
/** Preserved XLSX cache items by cache-field name (`PivotTable.cacheFields`). */
|
|
100
|
+
const preservedCacheFields = (pivot) => new Map((pivot.cacheFields ?? []).map((field) => [field.name, field]));
|
|
101
|
+
/**
|
|
102
|
+
* Preserved `<sharedItems …>`: its attributes, `count` only with an item list
|
|
103
|
+
* (Excel's form — a numeric field keeps just its type attributes), children
|
|
104
|
+
* in document order (`<s v/>`, `<n v/>`, `<m/>`… with any further attributes).
|
|
105
|
+
*/
|
|
106
|
+
const buildSharedItems = (shared) => el("sharedItems", {
|
|
107
|
+
...(shared.attributes ?? {}),
|
|
108
|
+
...(shared.items.length ? { count: String(shared.items.length) } : {}),
|
|
109
|
+
}, shared.items.map((item) => el(item.type, { v: item.value, ...(item.attributes ?? {}) })));
|
|
110
|
+
/** Preserved `<pivotField><items>`: `x`, `t`, the rest verbatim, in Excel's order. */
|
|
111
|
+
const buildFieldItems = (items) => el("items", { count: String(items.length) }, items.map((item) => el("item", {
|
|
112
|
+
...(item.x !== undefined ? { x: String(item.x) } : {}),
|
|
113
|
+
...(item.t !== undefined ? { t: item.t } : {}),
|
|
114
|
+
...(item.attributes ?? {}),
|
|
115
|
+
})));
|
|
83
116
|
/**
|
|
84
117
|
* Build pivotCacheDefinition XML for a pivot. The cacheSource
|
|
85
118
|
* points at the live worksheet range; `refreshOnLoad="1"` makes
|
|
@@ -96,35 +129,64 @@ export const buildPivotCacheDefinitionXml = (pivot, sheetName, fieldNames) => {
|
|
|
96
129
|
// Calculated fields are cache fields too (`databaseField="0"` +
|
|
97
130
|
// `formula`), listed after the source columns like Excel does.
|
|
98
131
|
const calculatedByName = new Map((pivot.calculatedFields ?? []).map((c) => [c.name, c.formula]));
|
|
132
|
+
const preserved = preservedCacheFields(pivot);
|
|
133
|
+
let preservedAny = false;
|
|
99
134
|
const cacheFields = fieldNames.map((name) => {
|
|
100
135
|
const formula = calculatedByName.get(name);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
136
|
+
if (formula !== undefined) {
|
|
137
|
+
return el("cacheField", { name, formula, databaseField: "0" });
|
|
138
|
+
}
|
|
139
|
+
const shared = preserved.get(name)?.sharedItems;
|
|
140
|
+
if (!shared)
|
|
141
|
+
return el("cacheField", { name }, [el("sharedItems", { count: "0" })]);
|
|
142
|
+
preservedAny = true;
|
|
143
|
+
return el("cacheField", { name }, [buildSharedItems(shared)]);
|
|
104
144
|
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
145
|
+
return buildDocument(el("pivotCacheDefinition", {
|
|
146
|
+
xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
|
147
|
+
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
148
|
+
invalid: "1",
|
|
149
|
+
refreshOnLoad: "1",
|
|
150
|
+
refreshedBy: "Rows n Columns",
|
|
151
|
+
recordCount: "0",
|
|
152
|
+
// Preserved item lists with no records part: Excel's own "don't save
|
|
153
|
+
// source data" shape (`saveData="0"`), rebuilt on open by refreshOnLoad.
|
|
154
|
+
...(preservedAny ? { saveData: "0" } : {}),
|
|
155
|
+
}, [
|
|
156
|
+
el("cacheSource", { type: "worksheet" }, [
|
|
157
|
+
el("worksheetSource", { ref: sourceRef, sheet: sheetName }),
|
|
158
|
+
]),
|
|
159
|
+
el("cacheFields", { count: String(cacheFields.length) }, cacheFields),
|
|
160
|
+
]));
|
|
161
|
+
};
|
|
162
|
+
/** `PivotArea` → `<pivotArea …><references count><reference … count><x v/>…` (Excel's `<x/>` order). */
|
|
163
|
+
const buildPivotArea = (area) => {
|
|
164
|
+
const references = area.references ?? [];
|
|
165
|
+
return el("pivotArea", area.attributes ?? {}, references.length
|
|
166
|
+
? [
|
|
167
|
+
el("references", { count: String(references.length) }, references.map((ref) => {
|
|
168
|
+
const items = ref.items ?? [];
|
|
169
|
+
return el("reference", { ...(ref.attributes ?? {}), count: String(items.length) }, items.map((v) => el("x", { v: String(v) })));
|
|
170
|
+
})),
|
|
171
|
+
]
|
|
172
|
+
: []);
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* `PivotTable.chartFormats` → `<chartFormats count><chartFormat chart
|
|
176
|
+
* format series><pivotArea>…`: the pivot areas a PivotChart's
|
|
177
|
+
* `<c:pivotFmt>` entries (`format`) format, keyed by the chart's
|
|
178
|
+
* `<c:fmtId>` (`chart`). Nothing is written without formats — Excel
|
|
179
|
+
* itself keeps `<c:pivotFmt>` entries with no `<chartFormat>`.
|
|
180
|
+
*/
|
|
181
|
+
const buildChartFormats = (pivot) => {
|
|
182
|
+
const formats = pivot.chartFormats ?? [];
|
|
183
|
+
if (!formats.length)
|
|
184
|
+
return undefined;
|
|
185
|
+
return el("chartFormats", { count: String(formats.length) }, formats.map((format) => el("chartFormat", {
|
|
186
|
+
chart: String(format.chart),
|
|
187
|
+
format: String(format.format),
|
|
188
|
+
...(format.series ? { series: "1" } : {}),
|
|
189
|
+
}, [buildPivotArea(format.pivotArea ?? {})])));
|
|
128
190
|
};
|
|
129
191
|
/**
|
|
130
192
|
* Build the pivotTable layout XML. Excel determines whether a cell
|
|
@@ -165,131 +227,122 @@ export const buildPivotTableXml = (pivot, cacheId, fieldIndices) => {
|
|
|
165
227
|
dataFieldIndices.add(idx);
|
|
166
228
|
}
|
|
167
229
|
const calculatedNames = new Set((pivot.calculatedFields ?? []).map((c) => c.name));
|
|
230
|
+
const preserved = preservedCacheFields(pivot);
|
|
168
231
|
// Need to emit one <pivotField> per cacheField in order, even
|
|
169
232
|
// for unused fields (Excel requires the array shapes match).
|
|
170
233
|
// Caller passes us the full field set via fieldIndices.
|
|
171
234
|
const sortedFieldIndices = [...fieldIndices.entries()].sort((a, b) => a[1] - b[1]);
|
|
172
235
|
for (const [name, idx] of sortedFieldIndices) {
|
|
173
236
|
const axis = fieldAxis.get(idx);
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
entry["@_dataField"] = "1";
|
|
237
|
+
const attributes = {
|
|
238
|
+
axis,
|
|
239
|
+
dataField: dataFieldIndices.has(idx) ? "1" : undefined,
|
|
240
|
+
};
|
|
179
241
|
if (calculatedNames.has(name)) {
|
|
180
242
|
// Excel pins calculated fields to the values area.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
243
|
+
pivotFields.push(el("pivotField", {
|
|
244
|
+
...attributes,
|
|
245
|
+
dragToRow: "0",
|
|
246
|
+
dragToCol: "0",
|
|
247
|
+
dragToPage: "0",
|
|
248
|
+
showAll: "0",
|
|
249
|
+
defaultSubtotal: "0",
|
|
250
|
+
}));
|
|
251
|
+
continue;
|
|
186
252
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
pivotFields.push(entry);
|
|
253
|
+
// Preserved `<items>` (C-84) keep Excel's item order — the indices the
|
|
254
|
+
// pivot's `<chartFormats>` pivot areas reference.
|
|
255
|
+
const items = preserved.get(name)?.items;
|
|
256
|
+
const children = items?.length ? [buildFieldItems(items)] : axis ? [el("items")] : [];
|
|
257
|
+
pivotFields.push(el("pivotField", { ...attributes, compact: "0" }, children));
|
|
193
258
|
}
|
|
194
|
-
const
|
|
259
|
+
const rowFieldIndices = (pivot.rows ?? [])
|
|
195
260
|
.map((r) => fieldIndices.get(r.field))
|
|
196
|
-
.filter((i) => i != null)
|
|
197
|
-
|
|
198
|
-
const colFields = (pivot.columns ?? [])
|
|
261
|
+
.filter((i) => i != null);
|
|
262
|
+
const colFieldIndices = (pivot.columns ?? [])
|
|
199
263
|
.map((c) => fieldIndices.get(c.field))
|
|
200
|
-
.filter((i) => i != null)
|
|
201
|
-
|
|
264
|
+
.filter((i) => i != null);
|
|
265
|
+
const axisFields = (indices) => indices.map((i) => el("field", { x: String(i) }));
|
|
202
266
|
// Running totals need a base field: Excel defaults to the first row
|
|
203
267
|
// field (falls back to the first column field / field 0).
|
|
204
|
-
const runTotalBase =
|
|
268
|
+
const runTotalBase = String(rowFieldIndices[0] ?? colFieldIndices[0] ?? 0);
|
|
205
269
|
const dataFields = (pivot.values ?? [])
|
|
206
270
|
.map((v) => {
|
|
207
271
|
const idx = fieldIndices.get(v.field);
|
|
208
272
|
if (idx == null)
|
|
209
273
|
return null;
|
|
210
|
-
const entry = {
|
|
211
|
-
"@_name": v.displayName ?? `${v.aggFunc} of ${v.field}`,
|
|
212
|
-
"@_fld": String(idx),
|
|
213
|
-
"@_subtotal": calculatedNames.has(v.field)
|
|
214
|
-
? "sum"
|
|
215
|
-
: aggToSubtotal(v.aggFunc),
|
|
216
|
-
};
|
|
217
274
|
const showDataAs = v.showAs ? SHOW_DATA_AS[v.showAs] : undefined;
|
|
218
|
-
if (showDataAs) {
|
|
219
|
-
entry["@_showDataAs"] = showDataAs;
|
|
220
|
-
if (showDataAs === "runTotal")
|
|
221
|
-
entry["@_baseField"] = runTotalBase;
|
|
222
|
-
}
|
|
223
275
|
const pivotShowAs = v.showAs ? X14_PIVOT_SHOW_AS[v.showAs] : undefined;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
276
|
+
return el("dataField", {
|
|
277
|
+
name: v.displayName ?? `${v.aggFunc} of ${v.field}`,
|
|
278
|
+
fld: String(idx),
|
|
279
|
+
subtotal: calculatedNames.has(v.field) ? "sum" : aggToSubtotal(v.aggFunc),
|
|
280
|
+
showDataAs,
|
|
281
|
+
baseField: showDataAs === "runTotal" ? runTotalBase : undefined,
|
|
282
|
+
}, pivotShowAs
|
|
283
|
+
? [
|
|
284
|
+
el("extLst", {}, [
|
|
285
|
+
el("ext", { uri: X14_DATA_FIELD_EXT_URI, "xmlns:x14": X14_NS }, [
|
|
286
|
+
el("x14:dataField", { pivotShowAs }),
|
|
287
|
+
]),
|
|
288
|
+
]),
|
|
289
|
+
]
|
|
290
|
+
: []);
|
|
234
291
|
})
|
|
235
292
|
.filter((d) => d !== null);
|
|
236
293
|
const styleInfo = pivot.styleInfo ?? {};
|
|
237
294
|
const styleFlag = (value, fallback) => value === undefined ? fallback : value ? "1" : "0";
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
},
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
},
|
|
290
|
-
},
|
|
291
|
-
};
|
|
292
|
-
return xmlBuilder.build(doc);
|
|
295
|
+
const chartFormats = buildChartFormats(pivot);
|
|
296
|
+
return buildDocument(el("pivotTableDefinition", {
|
|
297
|
+
xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
|
298
|
+
name: pivot.name ?? `PivotTable${pivot.pivotId}`,
|
|
299
|
+
cacheId: String(cacheId),
|
|
300
|
+
dataOnRows: "0",
|
|
301
|
+
applyNumberFormats: "0",
|
|
302
|
+
applyBorderFormats: "0",
|
|
303
|
+
applyFontFormats: "0",
|
|
304
|
+
applyPatternFormats: "0",
|
|
305
|
+
applyAlignmentFormats: "0",
|
|
306
|
+
applyWidthHeightFormats: "1",
|
|
307
|
+
dataCaption: "Values",
|
|
308
|
+
updatedVersion: "8",
|
|
309
|
+
minRefreshableVersion: "3",
|
|
310
|
+
showCalcMbrs: "0",
|
|
311
|
+
useAutoFormatting: "1",
|
|
312
|
+
itemPrintTitles: "1",
|
|
313
|
+
createdVersion: "8",
|
|
314
|
+
indent: "0",
|
|
315
|
+
outline: "1",
|
|
316
|
+
outlineData: "1",
|
|
317
|
+
multipleFieldFilters: "0",
|
|
318
|
+
rowGrandTotals: pivot.showRowGrandTotals === false ? "0" : "1",
|
|
319
|
+
colGrandTotals: pivot.showColumnGrandTotals === false ? "0" : "1",
|
|
320
|
+
}, [
|
|
321
|
+
el("location", { ref, firstHeaderRow: "1", firstDataRow: "1", firstDataCol: "1" }),
|
|
322
|
+
...(pivotFields.length
|
|
323
|
+
? [el("pivotFields", { count: String(pivotFields.length) }, pivotFields)]
|
|
324
|
+
: []),
|
|
325
|
+
...(rowFieldIndices.length
|
|
326
|
+
? [el("rowFields", { count: String(rowFieldIndices.length) }, axisFields(rowFieldIndices))]
|
|
327
|
+
: []),
|
|
328
|
+
...(colFieldIndices.length
|
|
329
|
+
? [el("colFields", { count: String(colFieldIndices.length) }, axisFields(colFieldIndices))]
|
|
330
|
+
: []),
|
|
331
|
+
...(dataFields.length
|
|
332
|
+
? [el("dataFields", { count: String(dataFields.length) }, dataFields)]
|
|
333
|
+
: []),
|
|
334
|
+
// CT_pivotTableDefinition order: chartFormats follows dataFields (and
|
|
335
|
+
// formats / conditionalFormats) and precedes pivotTableStyleInfo.
|
|
336
|
+
...(chartFormats ? [chartFormats] : []),
|
|
337
|
+
el("pivotTableStyleInfo", {
|
|
338
|
+
name: styleInfo.name || "PivotStyleLight16",
|
|
339
|
+
showRowHeaders: styleFlag(styleInfo.showRowHeaders, "1"),
|
|
340
|
+
showColHeaders: styleFlag(styleInfo.showColHeaders, "1"),
|
|
341
|
+
showRowStripes: styleFlag(styleInfo.showRowStripes, "0"),
|
|
342
|
+
showColStripes: styleFlag(styleInfo.showColStripes, "0"),
|
|
343
|
+
showLastColumn: styleFlag(styleInfo.showLastColumn, "1"),
|
|
344
|
+
}),
|
|
345
|
+
]));
|
|
293
346
|
};
|
|
294
347
|
/**
|
|
295
348
|
* Build the pivotTable.xml.rels file (links the pivot to its
|
|
@@ -300,16 +353,11 @@ export const buildPivotTableXml = (pivot, cacheId, fieldIndices) => {
|
|
|
300
353
|
* "../pivotCache/pivotCacheDefinition1.xml"
|
|
301
354
|
*/
|
|
302
355
|
export const buildPivotTableRelsXml = (cacheRid, cacheTarget) => {
|
|
303
|
-
|
|
304
|
-
"
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
"@_Target": cacheTarget,
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
};
|
|
314
|
-
return xmlBuilder.build(doc);
|
|
356
|
+
return buildDocument(el("Relationships", { xmlns: "http://schemas.openxmlformats.org/package/2006/relationships" }, [
|
|
357
|
+
el("Relationship", {
|
|
358
|
+
Id: cacheRid,
|
|
359
|
+
Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition",
|
|
360
|
+
Target: cacheTarget,
|
|
361
|
+
}),
|
|
362
|
+
]));
|
|
315
363
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CellData, CellFormat, Color, TextFormat } from "@rowsncolumns/spreadsheet";
|
|
1
|
+
import type { CellData, CellFormat, Color, TextFormat, BandedDefinition } from "@rowsncolumns/spreadsheet";
|
|
2
2
|
import { type CellXfs } from "@rowsncolumns/spreadsheet-state";
|
|
3
3
|
type NamedCellStyleRecord = {
|
|
4
4
|
name: string;
|
|
@@ -8,7 +8,7 @@ type NamedCellStyleRecord = {
|
|
|
8
8
|
hidden?: boolean;
|
|
9
9
|
customBuiltin?: boolean;
|
|
10
10
|
};
|
|
11
|
-
type CustomTableStyleRecord = {
|
|
11
|
+
export type CustomTableStyleRecord = {
|
|
12
12
|
name: string;
|
|
13
13
|
pivot?: boolean;
|
|
14
14
|
elements: Array<{
|
|
@@ -20,6 +20,12 @@ type CustomTableStyleRecord = {
|
|
|
20
20
|
italic?: boolean;
|
|
21
21
|
}>;
|
|
22
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* A `CustomTableStyle`'s banding as `<tableStyleElement>` records — the inverse of the parser's
|
|
25
|
+
* `getCustomTableStyleBanding` (header → `headerRow`, stripes, totals row with its bold, first /
|
|
26
|
+
* last column, column stripes). Elements without a colour or font are dropped (#668 T-103).
|
|
27
|
+
*/
|
|
28
|
+
export declare const tableStyleElementsFromBanding: (bandedRange: BandedDefinition) => CustomTableStyleRecord["elements"];
|
|
23
29
|
export declare class StyleBuilder {
|
|
24
30
|
private numberFormats;
|
|
25
31
|
private fonts;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style-builder.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/style-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,QAAQ,EACR,UAAU,EACV,KAAK,EAEL,UAAU,
|
|
1
|
+
{"version":3,"file":"style-builder.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/style-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,QAAQ,EACR,UAAU,EACV,KAAK,EAEL,UAAU,EACV,gBAAgB,EAEjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAwF/D,KAAK,oBAAoB,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAKF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,eAAe,CAAC,EAAE,KAAK,CAAC;QACxB,SAAS,CAAC,EAAE,KAAK,CAAC;QAClB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC,CAAC;CACJ,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GACxC,aAAa,gBAAgB,KAC5B,sBAAsB,CAAC,UAAU,CAqBnC,CAAC;AAEF,qBAAa,YAAY;IACvB,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,KAAK,CAKX;IACF,OAAO,CAAC,KAAK,CAA+D;IAC5E,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,eAAe,CAErB;IACF,OAAO,CAAC,iBAAiB,CAAgC;IAEzD;;;;;;;;;;;OAWG;IACH,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,EAAE;IAUlD;;;;;;;OAOG;IACH,oBAAoB,CAAC,OAAO,EAAE,sBAAsB,EAAE;IAOtD,OAAO,CAAC,OAAO,CAOb;IAEF,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,IAAI,CAAmB;IAC/B,OAAO,CAAC,MAAM,CAA6B;;IAU3C;;;;;;;OAOG;IACH,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI;IASzC,YAAY,CAAC,CAAC,SAAS,QAAQ,EAC7B,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAC1B,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS;IACnC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,UAAU,CAAC,cAAc,CAAC,GAC/C,MAAM;IAsET,0BAA0B,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI;IA0BrD,OAAO,CAAC,iBAAiB;IAoCzB,OAAO,CAAC,SAAS;IAcjB,OAAO,CAAC,SAAS;IA2DjB,OAAO,CAAC,WAAW;IA2BnB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,eAAe;IA8BvB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,YAAY;IAqCpB,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,YAAY;IAMpB,KAAK;CAuJN"}
|
|
@@ -7,6 +7,34 @@ const isStyleReference = (value) => !!value && typeof value === "object" && "sid
|
|
|
7
7
|
// numFmtId 47 per ECMA-376). Re-aliased for backwards compat with the
|
|
8
8
|
// previous local name in this file.
|
|
9
9
|
const BUILT_IN_NUMFMT_BY_PATTERN = BUILTIN_NUMFMT_BY_PATTERN;
|
|
10
|
+
/**
|
|
11
|
+
* A `CustomTableStyle`'s banding as `<tableStyleElement>` records — the inverse of the parser's
|
|
12
|
+
* `getCustomTableStyleBanding` (header → `headerRow`, stripes, totals row with its bold, first /
|
|
13
|
+
* last column, column stripes). Elements without a colour or font are dropped (#668 T-103).
|
|
14
|
+
*/
|
|
15
|
+
export const tableStyleElementsFromBanding = (bandedRange) => {
|
|
16
|
+
const rows = bandedRange.rowProperties ?? {};
|
|
17
|
+
const cols = bandedRange.columnProperties ?? {};
|
|
18
|
+
const elements = [];
|
|
19
|
+
const push = (type, backgroundColor, bold) => {
|
|
20
|
+
if (backgroundColor == null && !bold)
|
|
21
|
+
return;
|
|
22
|
+
elements.push({
|
|
23
|
+
type,
|
|
24
|
+
...(backgroundColor != null ? { backgroundColor: backgroundColor } : {}),
|
|
25
|
+
...(bold ? { bold: true } : {}),
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
push("headerRow", rows.headerColor);
|
|
29
|
+
push("firstRowStripe", rows.firstBandColor);
|
|
30
|
+
push("secondRowStripe", rows.secondBandColor);
|
|
31
|
+
push("totalRow", rows.totalRowColor, rows.totalRowBold === true);
|
|
32
|
+
push("firstColumn", rows.firstColumnColor);
|
|
33
|
+
push("lastColumn", rows.lastColumnColor);
|
|
34
|
+
push("firstColumnStripe", cols.firstBandColor);
|
|
35
|
+
push("secondColumnStripe", cols.secondBandColor);
|
|
36
|
+
return elements;
|
|
37
|
+
};
|
|
10
38
|
export class StyleBuilder {
|
|
11
39
|
numberFormats = [];
|
|
12
40
|
fonts = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CellData, Citation, CommentThread, DataValidationRuleRecord, IterativeCalculationOptions, SheetData, TextFormat } from "@rowsncolumns/common-types";
|
|
2
|
-
import type { Color, ConditionalFormatRule, EmbeddedChart, EmbeddedObject, NamedRange, PivotTable, ProtectedRange, Sheet, Slicer, SpreadsheetTheme, TableView } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import type { Color, ConditionalFormatRule, EmbeddedChart, EmbeddedObject, NamedRange, PivotTable, ProtectedRange, Sheet, Slicer, SpreadsheetTheme, TableView, CustomTableStyle } from "@rowsncolumns/spreadsheet";
|
|
3
3
|
import type { CellXfs, SharedStrings as SharedStringsType } from "@rowsncolumns/spreadsheet-state";
|
|
4
4
|
import type { PowerQueryParts } from "../../power-query";
|
|
5
5
|
import type { ExternalLink, WorkbookProperties } from "../../excel-parser/types";
|
|
@@ -70,7 +70,7 @@ export type ExportExcelProps<S extends Sheet, T extends CellData, C extends Cita
|
|
|
70
70
|
* are emitted regardless — Excel needs them as the fallback when a
|
|
71
71
|
* table doesn't pick a custom style.
|
|
72
72
|
*/
|
|
73
|
-
customTableStyles?: Array<{
|
|
73
|
+
customTableStyles?: Array<CustomTableStyle | {
|
|
74
74
|
name: string;
|
|
75
75
|
pivot?: boolean;
|
|
76
76
|
elements: Array<{
|