@rowsncolumns/toolkit 24.4.3 → 24.4.4
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/excel-parser/interface.d.ts +5 -1
- package/dist/cjs/excel-parser/interface.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/base/index.d.ts +2 -0
- package/dist/cjs/excel-parser/plugins/base/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/base/index.js +3 -0
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts +55 -9
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xls/index.js +487 -24
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsb/index.js +12 -5
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.d.ts +37 -0
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.js +244 -0
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts +70 -0
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.js +295 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts +9 -1
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/index.js +251 -104
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts +15 -1
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/styles.js +90 -4
- package/dist/cjs/excel-parser/registry.d.ts +7 -0
- package/dist/cjs/excel-parser/registry.d.ts.map +1 -1
- package/dist/cjs/excel-parser/registry.js +28 -1
- package/dist/cjs/excel-parser/types.d.ts +10 -1
- package/dist/cjs/excel-parser/types.d.ts.map +1 -1
- package/dist/cjs/excel-parser/workbook.d.ts +2 -0
- package/dist/cjs/excel-parser/workbook.d.ts.map +1 -1
- package/dist/cjs/excel-parser/workbook.js +20 -14
- package/dist/cjs/excel-parser/worker.js +128 -130
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/chart-builder.js +5 -33
- package/dist/cjs/exporter/xlsx/chartex-builder.d.ts +36 -0
- package/dist/cjs/exporter/xlsx/chartex-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/chartex-builder.js +109 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts +61 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.js +197 -0
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/xlsx-export.js +431 -193
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/excel-parser/interface.d.ts +5 -1
- package/dist/esm/excel-parser/interface.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/base/index.d.ts +2 -0
- package/dist/esm/excel-parser/plugins/base/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/base/index.js +3 -0
- package/dist/esm/excel-parser/plugins/xls/index.d.ts +55 -9
- package/dist/esm/excel-parser/plugins/xls/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xls/index.js +429 -23
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsb/index.js +10 -3
- package/dist/esm/excel-parser/plugins/xlsx/chartex.d.ts +37 -0
- package/dist/esm/excel-parser/plugins/xlsx/chartex.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/chartex.js +199 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts +70 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.js +246 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts +9 -1
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/index.js +92 -6
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts +15 -1
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/styles.js +80 -0
- package/dist/esm/excel-parser/registry.d.ts +7 -0
- package/dist/esm/excel-parser/registry.d.ts.map +1 -1
- package/dist/esm/excel-parser/registry.js +18 -1
- package/dist/esm/excel-parser/types.d.ts +10 -1
- package/dist/esm/excel-parser/types.d.ts.map +1 -1
- package/dist/esm/excel-parser/workbook.d.ts +2 -0
- package/dist/esm/excel-parser/workbook.d.ts.map +1 -1
- package/dist/esm/excel-parser/workbook.js +16 -10
- package/dist/esm/excel-parser/worker.js +10 -18
- package/dist/esm/exporter/xlsx/chart-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/chart-builder.js +0 -28
- package/dist/esm/exporter/xlsx/chartex-builder.d.ts +36 -0
- package/dist/esm/exporter/xlsx/chartex-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/chartex-builder.js +97 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.d.ts +61 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.js +173 -0
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/xlsx-export.js +228 -19
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/xlsx.d.ts +14 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EmbeddedChart, SheetRange, TreemapChart } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
/**
|
|
3
|
+
* Excel 2016+ "chartex" writer (`xl/charts/chartEx{N}.xml`) — the inverse
|
|
4
|
+
* of `excel-parser/plugins/xlsx/chartex.ts`. Treemap and sunburst have no
|
|
5
|
+
* `c:chartSpace` representation; Excel stores them as a `cx:chartSpace`
|
|
6
|
+
* whose series `layoutId` names the chart and whose data is a hierarchy
|
|
7
|
+
* `strDim type="cat"` (parent columns first, leaf last) plus a
|
|
8
|
+
* `numDim type="size"`. Anchored through `mc:AlternateContent` requiring the
|
|
9
|
+
* `cx1` namespace.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CHART_EX_REL_TYPE = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
|
|
12
|
+
export declare const CHART_EX_CONTENT_TYPE = "application/vnd.ms-office.chartex+xml";
|
|
13
|
+
export declare const CHART_EX_NS = "http://schemas.microsoft.com/office/drawing/2014/chartex";
|
|
14
|
+
/** Chart types that live in a chartex part rather than a `c:chartSpace`. */
|
|
15
|
+
export declare const isChartExType: (chartType: string | undefined | null) => chartType is "treemap" | "sunburst";
|
|
16
|
+
/**
|
|
17
|
+
* The hierarchy reference: parent columns + the leaf column merged into one
|
|
18
|
+
* contiguous range when they sit side by side on the same sheet over the same
|
|
19
|
+
* rows (how Excel lays a treemap out); otherwise the leaf labels alone.
|
|
20
|
+
*/
|
|
21
|
+
export declare const hierarchyRange: (spec: TreemapChart) => SheetRange | undefined;
|
|
22
|
+
/** `xl/charts/chartEx{N}.xml` for a treemap / sunburst; undefined when the spec has no data. */
|
|
23
|
+
export declare const buildChartExXml: (chart: EmbeddedChart, sheetNameById: Map<number, string>) => string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* The drawing anchor body for a chartex part: Excel's `mc:AlternateContent`
|
|
26
|
+
* with a `cx1`-requiring choice holding the graphic frame. No `mc:Fallback`
|
|
27
|
+
* is written — Excel opens the file without one, and a fallback text box
|
|
28
|
+
* would import as a stray shape in consumers that do not know chartex.
|
|
29
|
+
*/
|
|
30
|
+
export declare const buildChartExGraphicFrameXml: ({ relId, frameId, widthEmu, heightEmu, }: {
|
|
31
|
+
relId: string;
|
|
32
|
+
frameId: number;
|
|
33
|
+
widthEmu: number;
|
|
34
|
+
heightEmu: number;
|
|
35
|
+
}) => string;
|
|
36
|
+
//# sourceMappingURL=chartex-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chartex-builder.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/chartex-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,aAAa,EACb,UAAU,EACV,YAAY,EACb,MAAM,2BAA2B,CAAC;AAGnC;;;;;;;;GAQG;AAEH,eAAO,MAAM,iBAAiB,mEACoC,CAAC;AACnE,eAAO,MAAM,qBAAqB,0CAA0C,CAAC;AAC7E,eAAO,MAAM,WAAW,6DAA6D,CAAC;AAyBtF,4EAA4E;AAC5E,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,GAAG,SAAS,GAAG,IAAI,wCACb,CAAC;AAItD;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,YAAY,KAAG,UAAU,GAAG,SAsBhE,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,eAAe,GAC1B,OAAO,aAAa,EACpB,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,MAAM,GAAG,SAkCX,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,GAAI,0CAKzC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,WACkhB,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { cellRangeToAddress } from "@rowsncolumns/utils";
|
|
2
|
+
/**
|
|
3
|
+
* Excel 2016+ "chartex" writer (`xl/charts/chartEx{N}.xml`) — the inverse
|
|
4
|
+
* of `excel-parser/plugins/xlsx/chartex.ts`. Treemap and sunburst have no
|
|
5
|
+
* `c:chartSpace` representation; Excel stores them as a `cx:chartSpace`
|
|
6
|
+
* whose series `layoutId` names the chart and whose data is a hierarchy
|
|
7
|
+
* `strDim type="cat"` (parent columns first, leaf last) plus a
|
|
8
|
+
* `numDim type="size"`. Anchored through `mc:AlternateContent` requiring the
|
|
9
|
+
* `cx1` namespace.
|
|
10
|
+
*/
|
|
11
|
+
export const CHART_EX_REL_TYPE = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
|
|
12
|
+
export const CHART_EX_CONTENT_TYPE = "application/vnd.ms-office.chartex+xml";
|
|
13
|
+
export const CHART_EX_NS = "http://schemas.microsoft.com/office/drawing/2014/chartex";
|
|
14
|
+
const CHART_EX_1_NS = "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex";
|
|
15
|
+
const A_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
|
|
16
|
+
const R_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
17
|
+
const MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
|
|
18
|
+
const XML_DECLARATION = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n`;
|
|
19
|
+
/** `{XXXXXXXX-XXXX-4XXX-XXXX-XXXXXXXXXXXX}` — the series `uniqueId` Excel expects. */
|
|
20
|
+
const guid = () => {
|
|
21
|
+
const hex = () => Math.floor(Math.random() * 16).toString(16).toUpperCase();
|
|
22
|
+
const block = (n) => Array.from({ length: n }, hex).join("");
|
|
23
|
+
return `{${block(8)}-${block(4)}-4${block(3)}-${block(4)}-${block(12)}}`;
|
|
24
|
+
};
|
|
25
|
+
/** `'Sheet'!A2:B9` → `'Sheet'!$A$2:$B$9` — Excel writes chart data references absolute. */
|
|
26
|
+
const absoluteRef = (ref) => {
|
|
27
|
+
const bang = ref.lastIndexOf("!");
|
|
28
|
+
const sheetPart = bang >= 0 ? ref.slice(0, bang + 1) : "";
|
|
29
|
+
const cells = bang >= 0 ? ref.slice(bang + 1) : ref;
|
|
30
|
+
return `${sheetPart}${cells.replace(/\$?([A-Z]+)\$?(\d+)/g, "$$$1$$$2")}`;
|
|
31
|
+
};
|
|
32
|
+
const escapeText = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
33
|
+
/** Chart types that live in a chartex part rather than a `c:chartSpace`. */
|
|
34
|
+
export const isChartExType = (chartType) => chartType === "treemap" || chartType === "sunburst";
|
|
35
|
+
const primarySource = (entry) => entry?.sources?.[0];
|
|
36
|
+
/**
|
|
37
|
+
* The hierarchy reference: parent columns + the leaf column merged into one
|
|
38
|
+
* contiguous range when they sit side by side on the same sheet over the same
|
|
39
|
+
* rows (how Excel lays a treemap out); otherwise the leaf labels alone.
|
|
40
|
+
*/
|
|
41
|
+
export const hierarchyRange = (spec) => {
|
|
42
|
+
const leaf = primarySource(spec.labels?.[0]);
|
|
43
|
+
if (!leaf)
|
|
44
|
+
return undefined;
|
|
45
|
+
const parents = (spec.parentLabels ?? [])
|
|
46
|
+
.map((entry) => primarySource(entry))
|
|
47
|
+
.filter((range) => Boolean(range));
|
|
48
|
+
if (!parents.length)
|
|
49
|
+
return leaf;
|
|
50
|
+
const sameRows = parents.every((p) => p.sheetId === leaf.sheetId &&
|
|
51
|
+
p.startRowIndex === leaf.startRowIndex &&
|
|
52
|
+
p.endRowIndex === leaf.endRowIndex);
|
|
53
|
+
if (!sameRows)
|
|
54
|
+
return leaf;
|
|
55
|
+
const columns = [...parents, leaf].map((r) => r.startColumnIndex).sort((a, b) => a - b);
|
|
56
|
+
const contiguous = columns.every((c, i) => i === 0 || c === columns[i - 1] + 1);
|
|
57
|
+
if (!contiguous || columns[columns.length - 1] !== leaf.startColumnIndex) {
|
|
58
|
+
return leaf;
|
|
59
|
+
}
|
|
60
|
+
return { ...leaf, startColumnIndex: columns[0], endColumnIndex: leaf.endColumnIndex };
|
|
61
|
+
};
|
|
62
|
+
/** `xl/charts/chartEx{N}.xml` for a treemap / sunburst; undefined when the spec has no data. */
|
|
63
|
+
export const buildChartExXml = (chart, sheetNameById) => {
|
|
64
|
+
const spec = chart.spec;
|
|
65
|
+
if (!isChartExType(spec.chartType))
|
|
66
|
+
return undefined;
|
|
67
|
+
const cat = hierarchyRange(spec);
|
|
68
|
+
const size = primarySource(spec.sizeData?.[0]);
|
|
69
|
+
if (!cat || !size)
|
|
70
|
+
return undefined;
|
|
71
|
+
const catAddress = cellRangeToAddress(sheetNameById.get(cat.sheetId), cat);
|
|
72
|
+
const sizeAddress = cellRangeToAddress(sheetNameById.get(size.sheetId), size);
|
|
73
|
+
if (!catAddress || !sizeAddress)
|
|
74
|
+
return undefined;
|
|
75
|
+
const catRef = absoluteRef(catAddress);
|
|
76
|
+
const sizeRef = absoluteRef(sizeAddress);
|
|
77
|
+
const title = chart.spec.title;
|
|
78
|
+
const titleXml = title
|
|
79
|
+
? `<cx:title pos="t" align="ctr" overlay="0"><cx:tx><cx:txData><cx:v>${escapeText(title)}</cx:v></cx:txData></cx:tx></cx:title>`
|
|
80
|
+
: "";
|
|
81
|
+
const isTreemap = spec.chartType === "treemap";
|
|
82
|
+
const dataLabels = isTreemap
|
|
83
|
+
? `<cx:dataLabels pos="inEnd"><cx:visibility seriesName="0" categoryName="1" value="0"/></cx:dataLabels>`
|
|
84
|
+
: `<cx:dataLabels><cx:visibility seriesName="0" categoryName="1" value="0"/></cx:dataLabels>`;
|
|
85
|
+
const layoutPr = isTreemap
|
|
86
|
+
? `<cx:layoutPr><cx:parentLabelLayout val="banner"/></cx:layoutPr>`
|
|
87
|
+
: "";
|
|
88
|
+
const legend = isTreemap ? `<cx:legend pos="t" align="ctr" overlay="0"/>` : "";
|
|
89
|
+
return `${XML_DECLARATION}<cx:chartSpace xmlns:a="${A_NS}" xmlns:r="${R_NS}" xmlns:cx="${CHART_EX_NS}"><cx:chartData><cx:data id="0"><cx:strDim type="cat"><cx:f>${escapeText(catRef)}</cx:f></cx:strDim><cx:numDim type="size"><cx:f>${escapeText(sizeRef)}</cx:f></cx:numDim></cx:data></cx:chartData><cx:chart>${titleXml}<cx:plotArea><cx:plotAreaRegion><cx:series layoutId="${spec.chartType}" uniqueId="${guid()}">${dataLabels}<cx:dataId val="0"/>${layoutPr}</cx:series></cx:plotAreaRegion></cx:plotArea>${legend}</cx:chart></cx:chartSpace>`;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* The drawing anchor body for a chartex part: Excel's `mc:AlternateContent`
|
|
93
|
+
* with a `cx1`-requiring choice holding the graphic frame. No `mc:Fallback`
|
|
94
|
+
* is written — Excel opens the file without one, and a fallback text box
|
|
95
|
+
* would import as a stray shape in consumers that do not know chartex.
|
|
96
|
+
*/
|
|
97
|
+
export const buildChartExGraphicFrameXml = ({ relId, frameId, widthEmu, heightEmu, }) => `<mc:AlternateContent xmlns:mc="${MC_NS}"><mc:Choice xmlns:cx1="${CHART_EX_1_NS}" Requires="cx1"><xdr:graphicFrame macro=""><xdr:nvGraphicFramePr><xdr:cNvPr id="${frameId}" name="Chart ${frameId}"/><xdr:cNvGraphicFramePr/></xdr:nvGraphicFramePr><xdr:xfrm><a:off x="0" y="0"/><a:ext cx="${widthEmu}" cy="${heightEmu}"/></xdr:xfrm><a:graphic><a:graphicData uri="${CHART_EX_NS}"><cx:chart xmlns:cx="${CHART_EX_NS}" xmlns:r="${R_NS}" r:id="${relId}"/></a:graphicData></a:graphic></xdr:graphicFrame></mc:Choice></mc:AlternateContent>`;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { EmbedFormControlSpec } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
/**
|
|
3
|
+
* Excel form-control writers — the inverse of
|
|
4
|
+
* `excel-parser/plugins/xlsx/form-controls.ts`. A control is three parts:
|
|
5
|
+
* the worksheet `<controls><control>` entry (anchor + `<controlPr>`), its
|
|
6
|
+
* `xl/ctrlProps/ctrlPropN.xml` (`<formControlPr>`), and the legacy VML shape
|
|
7
|
+
* Excel actually draws (`<v:shape type="#_x0000_t201"><x:ClientData
|
|
8
|
+
* ObjectType="Checkbox">`). All three are written; Excel drops a control
|
|
9
|
+
* whose VML shape is missing.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CTRL_PROP_CONTENT_TYPE = "application/vnd.ms-excel.controlproperties+xml";
|
|
12
|
+
export declare const CTRL_PROP_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp";
|
|
13
|
+
export declare const FORM_CONTROL_NS = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main";
|
|
14
|
+
/** `xl/ctrlProps/ctrlPropN.xml` body. */
|
|
15
|
+
export declare const buildCtrlPropXml: (spec: EmbedFormControlSpec) => string;
|
|
16
|
+
/** A cell anchor in OOXML units: 0-based cell + EMU offsets. */
|
|
17
|
+
export type ControlCellAnchor = {
|
|
18
|
+
col: number;
|
|
19
|
+
colOff: number;
|
|
20
|
+
row: number;
|
|
21
|
+
rowOff: number;
|
|
22
|
+
};
|
|
23
|
+
/** One `<control>` element (inside the `<controls>` wrapper). */
|
|
24
|
+
export declare const buildControlElementXml: ({ spec, relId, shapeId, from, to, }: {
|
|
25
|
+
spec: EmbedFormControlSpec;
|
|
26
|
+
relId: string;
|
|
27
|
+
shapeId: number;
|
|
28
|
+
from: ControlCellAnchor;
|
|
29
|
+
to: ControlCellAnchor;
|
|
30
|
+
}) => string;
|
|
31
|
+
/**
|
|
32
|
+
* The worksheet `<controls>` element. Excel wraps controls in an
|
|
33
|
+
* `mc:AlternateContent` whose `Choice` requires the `x14` namespace; the
|
|
34
|
+
* namespaces the wrapper and the `xdr:` anchor cells need are declared on
|
|
35
|
+
* the element so the worksheet root stays untouched.
|
|
36
|
+
*/
|
|
37
|
+
export declare const buildControlsXml: (controlElements: string[]) => string;
|
|
38
|
+
/** VML `<v:shapetype>` every form control references (`#_x0000_t201`). */
|
|
39
|
+
export declare 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>";
|
|
40
|
+
/** Pixel geometry the VML shape needs (absolute position + cell-span anchor). */
|
|
41
|
+
export type FormControlVmlGeometry = {
|
|
42
|
+
leftPx: number;
|
|
43
|
+
topPx: number;
|
|
44
|
+
widthPx: number;
|
|
45
|
+
heightPx: number;
|
|
46
|
+
/** `x:Anchor` — from col, from col px offset, from row, from row px offset, to … */
|
|
47
|
+
anchor: [number, number, number, number, number, number, number, number];
|
|
48
|
+
};
|
|
49
|
+
/** One `<v:shape>` drawing a form control. */
|
|
50
|
+
export declare const buildFormControlVmlShape: ({ spec, shapeId, zIndex, geometry, }: {
|
|
51
|
+
spec: EmbedFormControlSpec;
|
|
52
|
+
shapeId: number;
|
|
53
|
+
zIndex: number;
|
|
54
|
+
geometry: FormControlVmlGeometry;
|
|
55
|
+
}) => string;
|
|
56
|
+
/** Wrap note + control shapes into one `vmlDrawing` part. */
|
|
57
|
+
export declare const buildVmlDrawingXml: ({ shapeTypes, shapes, }: {
|
|
58
|
+
shapeTypes: string[];
|
|
59
|
+
shapes: string[];
|
|
60
|
+
}) => string | undefined;
|
|
61
|
+
//# sourceMappingURL=form-controls-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-controls-builder.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/form-controls-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEtE;;;;;;;;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;AASF,iEAAiE;AACjE,eAAO,MAAM,sBAAsB,GAAI,qCAMpC;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;CACvB,KAAG,MAaH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,iBAAiB,MAAM,EAAE,KAAG,MAK5D,CAAC;AAmEF,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,sCAKtC;IACD,IAAI,EAAE,oBAAoB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,sBAAsB,CAAC;CAClC,KAAG,MAmBH,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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Excel form-control writers — the inverse of
|
|
3
|
+
* `excel-parser/plugins/xlsx/form-controls.ts`. A control is three parts:
|
|
4
|
+
* the worksheet `<controls><control>` entry (anchor + `<controlPr>`), its
|
|
5
|
+
* `xl/ctrlProps/ctrlPropN.xml` (`<formControlPr>`), and the legacy VML shape
|
|
6
|
+
* Excel actually draws (`<v:shape type="#_x0000_t201"><x:ClientData
|
|
7
|
+
* ObjectType="Checkbox">`). All three are written; Excel drops a control
|
|
8
|
+
* whose VML shape is missing.
|
|
9
|
+
*/
|
|
10
|
+
export const CTRL_PROP_CONTENT_TYPE = "application/vnd.ms-excel.controlproperties+xml";
|
|
11
|
+
export const CTRL_PROP_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp";
|
|
12
|
+
export const FORM_CONTROL_NS = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main";
|
|
13
|
+
const MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
|
|
14
|
+
const XDR_NS = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
|
|
15
|
+
const XML_DECLARATION = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n`;
|
|
16
|
+
const escapeAttr = (value) => value
|
|
17
|
+
.replace(/&/g, "&")
|
|
18
|
+
.replace(/</g, "<")
|
|
19
|
+
.replace(/>/g, ">")
|
|
20
|
+
.replace(/"/g, """);
|
|
21
|
+
const escapeText = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
22
|
+
const attrsXml = (attrs) => Object.entries(attrs ?? {})
|
|
23
|
+
.filter(([key, value]) => key && value != null)
|
|
24
|
+
.map(([key, value]) => ` ${key}="${escapeAttr(String(value))}"`)
|
|
25
|
+
.join("");
|
|
26
|
+
/** `xl/ctrlProps/ctrlPropN.xml` body. */
|
|
27
|
+
export const buildCtrlPropXml = (spec) => {
|
|
28
|
+
const { objectType: _ignored, ...rest } = spec.properties ?? {};
|
|
29
|
+
const items = (spec.listItems ?? [])
|
|
30
|
+
.map((item) => `<item val="${escapeAttr(item)}"/>`)
|
|
31
|
+
.join("");
|
|
32
|
+
const body = items ? `<itemLst>${items}</itemLst>` : "";
|
|
33
|
+
const open = `<formControlPr xmlns="${FORM_CONTROL_NS}" objectType="${escapeAttr(spec.objectType)}"${attrsXml(rest)}`;
|
|
34
|
+
return `${XML_DECLARATION}${body ? `${open}>${body}</formControlPr>` : `${open}/>`}`;
|
|
35
|
+
};
|
|
36
|
+
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
|
+
/** One `<control>` element (inside the `<controls>` wrapper). */
|
|
38
|
+
export const buildControlElementXml = ({ spec, relId, shapeId, from, to, }) => {
|
|
39
|
+
const name = spec.name ?? `${spec.objectType} ${shapeId}`;
|
|
40
|
+
const anchorAttrs = (spec.moveWithCells ? ' moveWithCells="1"' : "") +
|
|
41
|
+
(spec.sizeWithCells ? ' sizeWithCells="1"' : "");
|
|
42
|
+
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
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* The worksheet `<controls>` element. Excel wraps controls in an
|
|
46
|
+
* `mc:AlternateContent` whose `Choice` requires the `x14` namespace; the
|
|
47
|
+
* namespaces the wrapper and the `xdr:` anchor cells need are declared on
|
|
48
|
+
* the element so the worksheet root stays untouched.
|
|
49
|
+
*/
|
|
50
|
+
export const buildControlsXml = (controlElements) => {
|
|
51
|
+
if (!controlElements.length)
|
|
52
|
+
return "";
|
|
53
|
+
return `<controls xmlns:mc="${MC_NS}" xmlns:xdr="${XDR_NS}" xmlns:x14="${FORM_CONTROL_NS}"><mc:AlternateContent><mc:Choice Requires="x14">${controlElements.join("")}</mc:Choice></mc:AlternateContent></controls>`;
|
|
54
|
+
};
|
|
55
|
+
/** `formControlPr/@objectType` → VML `x:ClientData/@ObjectType`. */
|
|
56
|
+
const VML_OBJECT_TYPE = {
|
|
57
|
+
CheckBox: "Checkbox",
|
|
58
|
+
EditBox: "Edit",
|
|
59
|
+
};
|
|
60
|
+
const truthy = (value) => value === "1" || value === "true";
|
|
61
|
+
/**
|
|
62
|
+
* `x:ClientData` children derived from the `formControlPr` / `controlPr`
|
|
63
|
+
* attributes — Excel reads the control's state (checked, linked cell, list
|
|
64
|
+
* range, selection, scroll values) from the VML, the ctrlProp part is the
|
|
65
|
+
* x14 mirror.
|
|
66
|
+
*/
|
|
67
|
+
const clientDataChildrenXml = (spec) => {
|
|
68
|
+
const p = spec.properties ?? {};
|
|
69
|
+
const c = spec.controlProperties ?? {};
|
|
70
|
+
const out = [];
|
|
71
|
+
const push = (tag, value) => {
|
|
72
|
+
if (value === undefined)
|
|
73
|
+
out.push(`<x:${tag}/>`);
|
|
74
|
+
else
|
|
75
|
+
out.push(`<x:${tag}>${escapeText(value)}</x:${tag}>`);
|
|
76
|
+
};
|
|
77
|
+
if (spec.moveWithCells)
|
|
78
|
+
push("MoveWithCells");
|
|
79
|
+
if (spec.sizeWithCells)
|
|
80
|
+
push("SizeWithCells");
|
|
81
|
+
// Anchor is inserted by the caller (needs sheet geometry).
|
|
82
|
+
out.push("__ANCHOR__");
|
|
83
|
+
if (c.locked === "0")
|
|
84
|
+
push("Locked", "False");
|
|
85
|
+
if (c.defaultSize === "0")
|
|
86
|
+
push("DefaultSize", "False");
|
|
87
|
+
if (c.print === "0")
|
|
88
|
+
push("PrintObject", "False");
|
|
89
|
+
if (c.autoFill === "0")
|
|
90
|
+
push("AutoFill", "False");
|
|
91
|
+
if (c.autoLine === "0")
|
|
92
|
+
push("AutoLine", "False");
|
|
93
|
+
if (c.autoPict === "0")
|
|
94
|
+
push("AutoPict", "False");
|
|
95
|
+
if (c.macro)
|
|
96
|
+
push("FmlaMacro", c.macro);
|
|
97
|
+
if (p.textHAlign)
|
|
98
|
+
push("TextHAlign", p.textHAlign);
|
|
99
|
+
if (p.textVAlign)
|
|
100
|
+
push("TextVAlign", p.textVAlign);
|
|
101
|
+
if (truthy(p.lockText))
|
|
102
|
+
push("LockText");
|
|
103
|
+
if (truthy(p.justLastX))
|
|
104
|
+
push("JustLastX");
|
|
105
|
+
if (truthy(p.passwordEdit))
|
|
106
|
+
push("SecretEdit");
|
|
107
|
+
if (truthy(p.multiLine))
|
|
108
|
+
push("MultiLine");
|
|
109
|
+
if (truthy(p.verticalBar))
|
|
110
|
+
push("VScroll");
|
|
111
|
+
if (p.fmlaRange)
|
|
112
|
+
push("FmlaRange", p.fmlaRange);
|
|
113
|
+
if (p.widthMin)
|
|
114
|
+
push("WidthMin", p.widthMin);
|
|
115
|
+
if (p.sel)
|
|
116
|
+
push("Sel", p.sel);
|
|
117
|
+
if (p.seltype)
|
|
118
|
+
push("SelType", p.seltype);
|
|
119
|
+
if (p.multiSel)
|
|
120
|
+
push("MultiSel", p.multiSel);
|
|
121
|
+
if (p.dropStyle)
|
|
122
|
+
push("DropStyle", p.dropStyle);
|
|
123
|
+
if (truthy(p.colored))
|
|
124
|
+
push("Colored");
|
|
125
|
+
if (p.dropLines)
|
|
126
|
+
push("DropLines", p.dropLines);
|
|
127
|
+
if (p.checked === "Checked")
|
|
128
|
+
push("Checked", "1");
|
|
129
|
+
else if (p.checked === "Mixed")
|
|
130
|
+
push("Checked", "2");
|
|
131
|
+
if (p.fmlaLink)
|
|
132
|
+
push("FmlaLink", p.fmlaLink);
|
|
133
|
+
if (truthy(p.noThreeD))
|
|
134
|
+
push("NoThreeD");
|
|
135
|
+
if (truthy(p.firstButton))
|
|
136
|
+
push("FirstButton");
|
|
137
|
+
if (p.fmlaGroup)
|
|
138
|
+
push("FmlaGroup", p.fmlaGroup);
|
|
139
|
+
if (p.val)
|
|
140
|
+
push("Val", p.val);
|
|
141
|
+
if (p.min)
|
|
142
|
+
push("Min", p.min);
|
|
143
|
+
if (p.max)
|
|
144
|
+
push("Max", p.max);
|
|
145
|
+
if (p.inc)
|
|
146
|
+
push("Inc", p.inc);
|
|
147
|
+
if (p.page)
|
|
148
|
+
push("Page", p.page);
|
|
149
|
+
if (truthy(p.horiz))
|
|
150
|
+
push("Horiz");
|
|
151
|
+
if (p.dx)
|
|
152
|
+
push("Dx", p.dx);
|
|
153
|
+
return out.join("");
|
|
154
|
+
};
|
|
155
|
+
/** VML `<v:shapetype>` every form control references (`#_x0000_t201`). */
|
|
156
|
+
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
|
+
const toPt = (px) => `${(px * 0.75).toFixed(2).replace(/\.?0+$/, "")}pt`;
|
|
158
|
+
/** One `<v:shape>` drawing a form control. */
|
|
159
|
+
export const buildFormControlVmlShape = ({ spec, shapeId, zIndex, geometry, }) => {
|
|
160
|
+
const objectType = VML_OBJECT_TYPE[spec.objectType] ?? spec.objectType;
|
|
161
|
+
const caption = spec.text
|
|
162
|
+
? `<div style="text-align:left"><font face="Tahoma" size="160" color="auto">${escapeText(spec.text)}</font></div>`
|
|
163
|
+
: "";
|
|
164
|
+
const clientData = clientDataChildrenXml(spec).replace("__ANCHOR__", `<x:Anchor>${geometry.anchor.join(", ")}</x:Anchor>`);
|
|
165
|
+
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
|
+
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
|
+
};
|
|
168
|
+
/** Wrap note + control shapes into one `vmlDrawing` part. */
|
|
169
|
+
export const buildVmlDrawingXml = ({ shapeTypes, shapes, }) => {
|
|
170
|
+
if (!shapes.length)
|
|
171
|
+
return undefined;
|
|
172
|
+
return `<xml xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel"><o:shapelayout v:ext="edit"><o:idmap v:ext="edit" data="1"/></o:shapelayout>${shapeTypes.join("")}${shapes.join("")}</xml>`;
|
|
173
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xlsx-export.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/xlsx-export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,QAAQ,EACR,aAAa,EAEb,wBAAwB,EAGxB,2BAA2B,EAI3B,SAAS,EACT,UAAU,EAEX,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAGV,KAAK,EAEL,qBAAqB,EAErB,aAAa,EACb,cAAc,EAKd,UAAU,EACV,UAAU,EAEV,cAAc,EAMd,KAAK,EAEL,MAAM,EACN,gBAAgB,EAEhB,SAAS,
|
|
1
|
+
{"version":3,"file":"xlsx-export.d.ts","sourceRoot":"","sources":["../../../../exporter/xlsx/xlsx-export.ts"],"names":[],"mappings":"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"}
|