@shbernal/ts-xlsx 2.0.0 → 2.1.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 +20 -10
- package/dist/bytes.d.ts +24 -0
- package/dist/bytes.js +34 -0
- package/dist/core/address.d.ts +26 -4
- package/dist/core/address.js +21 -9
- package/dist/core/autofilter.d.ts +11 -0
- package/dist/core/autofilter.js +35 -10
- package/dist/core/color-resolution.d.ts +1 -1
- package/dist/core/color-resolution.js +7 -8
- package/dist/core/conditional-formatting-overlay.d.ts +5 -0
- package/dist/core/conditional-formatting-overlay.js +11 -0
- package/dist/core/conditional-formatting.d.ts +45 -5
- package/dist/core/conditional-formatting.js +88 -0
- package/dist/core/data-validation-overlay.d.ts +11 -0
- package/dist/core/data-validation-overlay.js +21 -2
- package/dist/core/data-validation.d.ts +9 -2
- package/dist/core/data-validation.js +34 -0
- package/dist/core/grid-edits.d.ts +16 -0
- package/dist/core/grid-edits.js +26 -8
- package/dist/core/grid-shift.d.ts +19 -0
- package/dist/core/grid-shift.js +8 -0
- package/dist/core/image.d.ts +2 -0
- package/dist/core/image.js +4 -0
- package/dist/core/merge.d.ts +12 -1
- package/dist/core/merge.js +36 -2
- package/dist/core/page-setup.d.ts +16 -2
- package/dist/core/page-setup.js +8 -1
- package/dist/core/pivot-table.d.ts +2 -0
- package/dist/core/pivot-table.js +25 -16
- package/dist/core/protection.d.ts +3 -0
- package/dist/core/protection.js +20 -14
- package/dist/core/row-input.d.ts +7 -0
- package/dist/core/row-input.js +10 -8
- package/dist/core/style.d.ts +27 -0
- package/dist/core/style.js +82 -67
- package/dist/core/table.d.ts +25 -11
- package/dist/core/table.js +67 -31
- package/dist/core/theme.d.ts +3 -1
- package/dist/core/theme.js +4 -0
- package/dist/core/workbook.d.ts +2 -2
- package/dist/core/worksheet-comments.d.ts +8 -0
- package/dist/core/worksheet-comments.js +18 -0
- package/dist/core/worksheet.d.ts +15 -2
- package/dist/core/worksheet.js +28 -48
- package/dist/customui/ribbon.js +24 -23
- package/dist/entries/core.d.ts +3 -3
- package/dist/entries/csv.d.ts +1 -1
- package/dist/entries/node-unavailable.d.ts +15 -0
- package/dist/entries/node-unavailable.js +20 -0
- package/dist/entries/node.d.ts +1 -0
- package/dist/entries/node.js +1 -0
- package/dist/entries/xlsx.d.ts +0 -1
- package/dist/entries/xlsx.js +0 -1
- package/dist/io/csv/read.js +1 -1
- package/dist/io/csv/write.d.ts +12 -2
- package/dist/io/csv/write.js +17 -2
- package/dist/io/opc/inflate.js +2 -12
- package/dist/io/opc/rels.d.ts +11 -0
- package/dist/io/opc/rels.js +3 -2
- package/dist/io/style/xf-style.d.ts +7 -2
- package/dist/io/style/xf-style.js +6 -1
- package/dist/io/xlsx/cell-accumulator.d.ts +1 -3
- package/dist/io/xlsx/cell-accumulator.js +20 -58
- package/dist/io/xlsx/cell-value.d.ts +1 -1
- package/dist/io/xlsx/cell-value.js +7 -4
- package/dist/io/xlsx/color-xml.d.ts +1 -1
- package/dist/io/xlsx/color-xml.js +7 -6
- package/dist/io/xlsx/comments.js +4 -2
- package/dist/io/xlsx/conditional-formatting.d.ts +1 -1
- package/dist/io/xlsx/conditional-formatting.js +60 -45
- package/dist/io/xlsx/data-validation.d.ts +1 -1
- package/dist/io/xlsx/data-validation.js +35 -33
- package/dist/io/xlsx/hyperlinks.js +6 -14
- package/dist/io/xlsx/images.js +19 -22
- package/dist/io/xlsx/read-pivot.js +2 -8
- package/dist/io/xlsx/read-shared-strings.js +8 -47
- package/dist/io/xlsx/read-styles.js +2 -1
- package/dist/io/xlsx/read-worksheet.js +14 -16
- package/dist/io/xlsx/read.d.ts +1 -1
- package/dist/io/xlsx/read.js +44 -74
- package/dist/io/xlsx/rich-runs.d.ts +41 -7
- package/dist/io/xlsx/rich-runs.js +94 -30
- package/dist/io/xlsx/sheet-properties.d.ts +1 -1
- package/dist/io/xlsx/sheet-properties.js +13 -9
- package/dist/io/xlsx/styles.d.ts +3 -15
- package/dist/io/xlsx/styles.js +63 -88
- package/dist/io/xlsx/tables.js +13 -13
- package/dist/io/xlsx/theme-xml.js +7 -4
- package/dist/io/xlsx/threaded-comments.js +19 -19
- package/dist/io/xlsx/workbook-xml.js +14 -8
- package/dist/io/xlsx/worksheet-xml.js +34 -37
- package/dist/io/xlsx/write-stream.d.ts +8 -1
- package/dist/io/xlsx/write-stream.js +10 -11
- package/dist/sha512.d.ts +2 -0
- package/dist/sha512.js +146 -0
- package/dist/vba/bytes.d.ts +1 -2
- package/dist/vba/bytes.js +1 -12
- package/dist/vba/dir-records.d.ts +53 -0
- package/dist/vba/dir-records.js +28 -0
- package/dist/vba/project-editor.js +5 -34
- package/dist/vba/project.js +2 -18
- package/dist/xml/xml-read.d.ts +60 -0
- package/dist/xml/xml-read.js +47 -0
- package/dist/xml/xml.d.ts +43 -1
- package/dist/xml/xml.js +17 -5
- package/package.json +21 -4
package/dist/core/style.js
CHANGED
|
@@ -1,83 +1,93 @@
|
|
|
1
|
-
const NAMED_UNDERLINE_STYLES =
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
const NAMED_UNDERLINE_STYLES = {
|
|
2
|
+
none: true,
|
|
3
|
+
single: true,
|
|
4
|
+
double: true,
|
|
5
|
+
singleAccounting: true,
|
|
6
|
+
doubleAccounting: true,
|
|
7
|
+
};
|
|
8
8
|
export function isNamedUnderlineStyle(value) {
|
|
9
|
-
return
|
|
9
|
+
return Object.hasOwn(NAMED_UNDERLINE_STYLES, value);
|
|
10
|
+
}
|
|
11
|
+
export function parseArgb(value) {
|
|
12
|
+
const hex = value.startsWith('#') ? value.slice(1) : value;
|
|
13
|
+
const argb = hex.length === 6 ? `FF${hex}` : hex;
|
|
14
|
+
return /^[0-9a-fA-F]{8}$/.test(argb) ? argb : undefined;
|
|
10
15
|
}
|
|
11
|
-
const FILL_PATTERN_TYPES =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
const FILL_PATTERN_TYPES = {
|
|
17
|
+
none: true,
|
|
18
|
+
solid: true,
|
|
19
|
+
gray125: true,
|
|
20
|
+
darkGray: true,
|
|
21
|
+
mediumGray: true,
|
|
22
|
+
lightGray: true,
|
|
23
|
+
gray0625: true,
|
|
24
|
+
darkHorizontal: true,
|
|
25
|
+
darkVertical: true,
|
|
26
|
+
darkDown: true,
|
|
27
|
+
darkUp: true,
|
|
28
|
+
darkGrid: true,
|
|
29
|
+
darkTrellis: true,
|
|
30
|
+
lightHorizontal: true,
|
|
31
|
+
lightVertical: true,
|
|
32
|
+
lightDown: true,
|
|
33
|
+
lightUp: true,
|
|
34
|
+
lightGrid: true,
|
|
35
|
+
lightTrellis: true,
|
|
36
|
+
};
|
|
32
37
|
export function isFillPatternType(value) {
|
|
33
|
-
return
|
|
38
|
+
return Object.hasOwn(FILL_PATTERN_TYPES, value);
|
|
34
39
|
}
|
|
35
|
-
const BORDER_STYLES =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
40
|
+
const BORDER_STYLES = {
|
|
41
|
+
thin: true,
|
|
42
|
+
medium: true,
|
|
43
|
+
thick: true,
|
|
44
|
+
dashed: true,
|
|
45
|
+
dotted: true,
|
|
46
|
+
double: true,
|
|
47
|
+
hair: true,
|
|
48
|
+
mediumDashed: true,
|
|
49
|
+
dashDot: true,
|
|
50
|
+
mediumDashDot: true,
|
|
51
|
+
dashDotDot: true,
|
|
52
|
+
mediumDashDotDot: true,
|
|
53
|
+
slantDashDot: true,
|
|
54
|
+
};
|
|
50
55
|
export function isBorderStyle(value) {
|
|
51
|
-
return
|
|
56
|
+
return Object.hasOwn(BORDER_STYLES, value);
|
|
52
57
|
}
|
|
58
|
+
const FONT_VERTICAL_ALIGNMENTS = {
|
|
59
|
+
superscript: true,
|
|
60
|
+
subscript: true,
|
|
61
|
+
};
|
|
53
62
|
export function isFontVerticalAlignment(value) {
|
|
54
|
-
return
|
|
63
|
+
return Object.hasOwn(FONT_VERTICAL_ALIGNMENTS, value);
|
|
55
64
|
}
|
|
65
|
+
const FONT_SCHEMES = { minor: true, major: true, none: true };
|
|
56
66
|
export function isFontScheme(value) {
|
|
57
|
-
return
|
|
67
|
+
return Object.hasOwn(FONT_SCHEMES, value);
|
|
58
68
|
}
|
|
59
|
-
const HORIZONTAL_ALIGNMENTS =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
const HORIZONTAL_ALIGNMENTS = {
|
|
70
|
+
general: true,
|
|
71
|
+
left: true,
|
|
72
|
+
center: true,
|
|
73
|
+
right: true,
|
|
74
|
+
fill: true,
|
|
75
|
+
justify: true,
|
|
76
|
+
centerContinuous: true,
|
|
77
|
+
distributed: true,
|
|
78
|
+
};
|
|
69
79
|
export function isHorizontalAlignment(value) {
|
|
70
|
-
return
|
|
80
|
+
return Object.hasOwn(HORIZONTAL_ALIGNMENTS, value);
|
|
71
81
|
}
|
|
72
|
-
const VERTICAL_ALIGNMENTS =
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
const VERTICAL_ALIGNMENTS = {
|
|
83
|
+
top: true,
|
|
84
|
+
center: true,
|
|
85
|
+
bottom: true,
|
|
86
|
+
justify: true,
|
|
87
|
+
distributed: true,
|
|
88
|
+
};
|
|
79
89
|
export function isVerticalAlignment(value) {
|
|
80
|
-
return
|
|
90
|
+
return Object.hasOwn(VERTICAL_ALIGNMENTS, value);
|
|
81
91
|
}
|
|
82
92
|
const CELL_STYLE_FACET_KEYS = {
|
|
83
93
|
fill: true,
|
|
@@ -92,6 +102,11 @@ export function assignStyleFacets(target, source) {
|
|
|
92
102
|
for (const facet of CELL_STYLE_FACETS)
|
|
93
103
|
copyFacet(target, source, facet);
|
|
94
104
|
}
|
|
105
|
+
export function pickStyleFacets(source) {
|
|
106
|
+
const facets = {};
|
|
107
|
+
assignStyleFacets(facets, source);
|
|
108
|
+
return facets;
|
|
109
|
+
}
|
|
95
110
|
function copyFacet(target, source, key) {
|
|
96
111
|
const value = source[key];
|
|
97
112
|
if (value !== undefined)
|
package/dist/core/table.d.ts
CHANGED
|
@@ -5,16 +5,30 @@ import type { CellValue } from './value.ts';
|
|
|
5
5
|
* bakes into the cells rather than storing as table metadata. Every facet ({@link CellStyle}) is
|
|
6
6
|
* optional; only the ones set are applied, leaving the rest of each cell's style untouched. */
|
|
7
7
|
export type TableColumnStyle = Readonly<CellStyle>;
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The channel a registered table holds into its owning worksheet's grid. A worksheet supplies it
|
|
10
|
+
* when it registers the table; a table built standalone (a unit test, a bare model) has none, so it
|
|
11
|
+
* can be inspected but cannot materialise or append cells, and appending throws rather than
|
|
12
|
+
* silently dropping the values.
|
|
13
|
+
*
|
|
14
|
+
* All three coordinates are 1-based.
|
|
15
|
+
*/
|
|
16
|
+
export interface TableGrid {
|
|
17
|
+
/**
|
|
18
|
+
* Whether the cell at this position already holds a value. The materialiser's round-trip guard
|
|
19
|
+
* asks this and nothing else: it must not create the cell, because asking whether a table's frame
|
|
20
|
+
* is already filled would otherwise fill the grid with the empty cells it was asking about.
|
|
21
|
+
*/
|
|
22
|
+
holdsValue(row: number, col: number): boolean;
|
|
23
|
+
/** Write a value, applying the column's style (if any) to the cell. */
|
|
24
|
+
writeCell(row: number, col: number, value: CellValue, style?: TableColumnStyle): void;
|
|
25
|
+
/**
|
|
26
|
+
* Insert one empty row at `row`, shifting that row and everything below it down by one: how a
|
|
27
|
+
* table with a totals row opens a slot for an appended data row above the totals. Relocating the
|
|
28
|
+
* totals row lives in the grid, which is why this is the grid's job and not the table's.
|
|
29
|
+
*/
|
|
30
|
+
insertRow(row: number): void;
|
|
31
|
+
}
|
|
18
32
|
/**
|
|
19
33
|
* A table's visual style (`<tableStyleInfo>`): the named style to apply plus the banding/highlight
|
|
20
34
|
* toggles. Every field is a tri-state so a round-trip stays faithful: a value present in the source
|
|
@@ -127,7 +141,7 @@ export declare class Table {
|
|
|
127
141
|
readonly totalsRowShown: boolean | undefined;
|
|
128
142
|
readonly autoFilter: boolean;
|
|
129
143
|
readonly style: TableStyleInfo | undefined;
|
|
130
|
-
constructor(options: TableOptions,
|
|
144
|
+
constructor(options: TableOptions, grid?: TableGrid);
|
|
131
145
|
get columnCount(): number;
|
|
132
146
|
/** The number of data rows (excludes the header and totals rows). Always defined: a table loaded
|
|
133
147
|
* from a file derives it from the stored range, so reading the height never throws. */
|
package/dist/core/table.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AuthoringError } from '../errors.js';
|
|
2
2
|
import { decodeCellRef, encodeAddress } from './address.js';
|
|
3
|
+
import { isDeletedSpan, shiftIndex } from './grid-shift.js';
|
|
3
4
|
function cloneStyleInfo(style) {
|
|
4
5
|
const clone = {};
|
|
5
6
|
if (style.name !== undefined && style.name !== 'None')
|
|
@@ -24,20 +25,20 @@ export const TOTALS_ROW_SUBTOTAL_CODE = {
|
|
|
24
25
|
sum: 109,
|
|
25
26
|
var: 110,
|
|
26
27
|
};
|
|
27
|
-
const TOTALS_ROW_FUNCTIONS =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
const TOTALS_ROW_FUNCTIONS = {
|
|
29
|
+
average: true,
|
|
30
|
+
countNums: true,
|
|
31
|
+
count: true,
|
|
32
|
+
max: true,
|
|
33
|
+
min: true,
|
|
34
|
+
stdDev: true,
|
|
35
|
+
sum: true,
|
|
36
|
+
var: true,
|
|
37
|
+
custom: true,
|
|
38
|
+
none: true,
|
|
39
|
+
};
|
|
39
40
|
export function isTotalsRowFunction(value) {
|
|
40
|
-
return
|
|
41
|
+
return Object.hasOwn(TOTALS_ROW_FUNCTIONS, value);
|
|
41
42
|
}
|
|
42
43
|
const IDENTIFIER = /^[\p{L}\\_][\p{L}\p{N}._]*$/u;
|
|
43
44
|
function disambiguateColumnNames(columns) {
|
|
@@ -71,9 +72,8 @@ export class Table {
|
|
|
71
72
|
#anchorCol;
|
|
72
73
|
#anchorRow;
|
|
73
74
|
#dataRowCount;
|
|
74
|
-
#
|
|
75
|
-
|
|
76
|
-
constructor(options, writeCell, insertRow) {
|
|
75
|
+
#grid;
|
|
76
|
+
constructor(options, grid) {
|
|
77
77
|
validateTableName(options.name);
|
|
78
78
|
if (options.columns.length === 0) {
|
|
79
79
|
throw new AuthoringError(`table "${options.name}" must declare at least one column`);
|
|
@@ -102,11 +102,12 @@ export class Table {
|
|
|
102
102
|
this.#anchorCol = col;
|
|
103
103
|
this.#anchorRow = row;
|
|
104
104
|
this.#dataRowCount = options.rowCount;
|
|
105
|
-
this.#
|
|
106
|
-
this.#insertRow = insertRow;
|
|
105
|
+
this.#grid = grid;
|
|
107
106
|
if (this.#rowSpan < 1) {
|
|
108
107
|
throw new AuthoringError(`table "${this.name}" has no rows: it needs a header row or at least one data row`);
|
|
109
108
|
}
|
|
109
|
+
if (grid !== undefined)
|
|
110
|
+
this.#materializeFrame(grid);
|
|
110
111
|
}
|
|
111
112
|
get columnCount() {
|
|
112
113
|
return this.columns.length;
|
|
@@ -119,32 +120,67 @@ export class Table {
|
|
|
119
120
|
throw new RangeError(`row has ${values.length} values but table "${this.name}" has ${this.columnCount} columns`);
|
|
120
121
|
}
|
|
121
122
|
const target = this.#anchorRow + (this.headerRow ? 1 : 0) + this.#dataRowCount;
|
|
123
|
+
const grid = this.#grid;
|
|
122
124
|
if (this.totalsRow) {
|
|
123
|
-
if (
|
|
125
|
+
if (grid === undefined) {
|
|
124
126
|
throw new AuthoringError(`table "${this.name}" is not attached to a worksheet: cannot relocate its totals row to append a data row`);
|
|
125
127
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
this.#writeCell?.(target, this.#anchorCol + index, value, this.columns[index]?.style);
|
|
129
|
-
});
|
|
128
|
+
grid.insertRow(target);
|
|
129
|
+
this.#writeRow(grid, target, values);
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
if (values.length > 0) {
|
|
133
|
-
if (
|
|
133
|
+
if (grid === undefined) {
|
|
134
134
|
throw new AuthoringError(`table "${this.name}" is not attached to a worksheet: cannot write appended row values`);
|
|
135
135
|
}
|
|
136
|
-
|
|
137
|
-
this.#writeCell?.(target, this.#anchorCol + index, value, this.columns[index]?.style);
|
|
138
|
-
});
|
|
136
|
+
this.#writeRow(grid, target, values);
|
|
139
137
|
}
|
|
140
138
|
this.#dataRowCount += 1;
|
|
141
139
|
}
|
|
140
|
+
#writeRow(grid, row, values) {
|
|
141
|
+
values.forEach((value, index) => {
|
|
142
|
+
grid.writeCell(row, this.#anchorCol + index, value, this.columns[index]?.style);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
#materializeFrame(grid) {
|
|
146
|
+
if (this.headerRow) {
|
|
147
|
+
const { top, left } = this.region;
|
|
148
|
+
this.columns.forEach((column, index) => {
|
|
149
|
+
const col = left + index;
|
|
150
|
+
if (grid.holdsValue(top, col))
|
|
151
|
+
return;
|
|
152
|
+
grid.writeCell(top, col, column.name);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (this.totalsRow) {
|
|
156
|
+
const { left, bottom } = this.region;
|
|
157
|
+
this.columns.forEach((column, index) => {
|
|
158
|
+
const col = left + index;
|
|
159
|
+
if (grid.holdsValue(bottom, col))
|
|
160
|
+
return;
|
|
161
|
+
if (column.totalsRowLabel !== undefined) {
|
|
162
|
+
grid.writeCell(bottom, col, column.totalsRowLabel);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (column.totalsRowFunction === undefined)
|
|
166
|
+
return;
|
|
167
|
+
const code = TOTALS_ROW_SUBTOTAL_CODE[column.totalsRowFunction];
|
|
168
|
+
if (code !== undefined) {
|
|
169
|
+
grid.writeCell(bottom, col, {
|
|
170
|
+
formula: `SUBTOTAL(${code},${this.name}[${column.name}])`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
else if (column.totalsRowFunction === 'custom' && column.totalsRowFormula !== undefined) {
|
|
174
|
+
grid.writeCell(bottom, col, { formula: column.totalsRowFormula });
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
142
179
|
shiftRows(start, count, delta) {
|
|
143
|
-
if (this.#anchorRow
|
|
180
|
+
if (isDeletedSpan(this.#anchorRow, this.#bottom, start, count))
|
|
144
181
|
return false;
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
const bottom = shift(this.#bottom);
|
|
182
|
+
const top = shiftIndex(this.#anchorRow, start, count, delta, 'row');
|
|
183
|
+
const bottom = shiftIndex(this.#bottom, start, count, delta, 'row');
|
|
148
184
|
const span = bottom - top + 1;
|
|
149
185
|
const fixedRows = (this.headerRow ? 1 : 0) + (this.totalsRow ? 1 : 0);
|
|
150
186
|
const dataRows = span - fixedRows;
|
package/dist/core/theme.d.ts
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
export declare const THEME_COLOR_SLOTS: readonly ['lt1', 'dk1', 'lt2', 'dk2', 'accent1', 'accent2', 'accent3', 'accent4', 'accent5', 'accent6', 'hlink', 'folHlink'];
|
|
16
16
|
/** One slot of a theme's colour scheme. */
|
|
17
17
|
export type ThemeColorSlot = (typeof THEME_COLOR_SLOTS)[number];
|
|
18
|
+
/** Narrow a raw `<a:clrScheme>` child name to a known {@link ThemeColorSlot}. */
|
|
19
|
+
export declare function isThemeColorSlot(value: string): value is ThemeColorSlot;
|
|
18
20
|
/**
|
|
19
21
|
* A theme's colour scheme: each slot's colour as a 6-hex `RRGGBB` string. Partial because a foreign
|
|
20
22
|
* theme is free to omit a slot (or express one in a colour model this reader does not decode), and an
|
|
@@ -22,7 +24,7 @@ export type ThemeColorSlot = (typeof THEME_COLOR_SLOTS)[number];
|
|
|
22
24
|
*/
|
|
23
25
|
export type ThemeColorScheme = Readonly<Partial<Record<ThemeColorSlot, string>>>;
|
|
24
26
|
/** The Office default colour scheme, matching the theme part the writer emits for a workbook with none. */
|
|
25
|
-
export declare const DEFAULT_THEME_COLOR_SCHEME:
|
|
27
|
+
export declare const DEFAULT_THEME_COLOR_SCHEME: Readonly<Record<ThemeColorSlot, string>>;
|
|
26
28
|
/**
|
|
27
29
|
* The two typefaces a theme nominates: the `major` face headings use and the `minor` face body text
|
|
28
30
|
* uses. A cell's font reaches them by `scheme="major"`/`scheme="minor"` instead of naming a typeface,
|
package/dist/core/theme.js
CHANGED
|
@@ -12,6 +12,10 @@ export const THEME_COLOR_SLOTS = [
|
|
|
12
12
|
'hlink',
|
|
13
13
|
'folHlink',
|
|
14
14
|
];
|
|
15
|
+
const THEME_COLOR_SLOT_NAMES = new Set(THEME_COLOR_SLOTS);
|
|
16
|
+
export function isThemeColorSlot(value) {
|
|
17
|
+
return THEME_COLOR_SLOT_NAMES.has(value);
|
|
18
|
+
}
|
|
15
19
|
export const DEFAULT_THEME_COLOR_SCHEME = {
|
|
16
20
|
lt1: 'FFFFFF',
|
|
17
21
|
dk1: '000000',
|
package/dist/core/workbook.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { type TableStyle } from './table-style.ts';
|
|
|
9
9
|
import { type ThemeColorScheme, type ThemeFontScheme, type ThemeOverrides } from './theme.ts';
|
|
10
10
|
import type { WorkbookProtection } from './workbook-protection.ts';
|
|
11
11
|
import { type DeclaredThemeSchemes } from './workbook-theme.ts';
|
|
12
|
-
import { Worksheet, type WorksheetState } from './worksheet.ts';
|
|
12
|
+
import { type Visibility, Worksheet, type WorksheetState } from './worksheet.ts';
|
|
13
13
|
/**
|
|
14
14
|
* A workbook-level reference to package content the model does not model: a pivot cache
|
|
15
15
|
* (`pivotCacheDefinition`) or a slicer cache (`slicerCache`), preserved verbatim across a round-trip
|
|
@@ -70,7 +70,7 @@ export interface WorkbookView {
|
|
|
70
70
|
/** 0-based index into {@link Workbook.worksheets} of the sheet selected on open. */
|
|
71
71
|
activeTab: number;
|
|
72
72
|
/** Window visibility; omit for a normally visible window. */
|
|
73
|
-
visibility?:
|
|
73
|
+
visibility?: Visibility;
|
|
74
74
|
/** Whether the document window opens minimised; omit for a restored window. */
|
|
75
75
|
minimized?: boolean;
|
|
76
76
|
}
|
|
@@ -5,5 +5,13 @@ export declare class WorksheetComments {
|
|
|
5
5
|
get threads(): readonly CommentThread[];
|
|
6
6
|
add(thread: CommentThread): void;
|
|
7
7
|
at(reference: string): CommentThread | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Re-anchor every conversation through a row or column splice. A thread hangs off exactly one cell,
|
|
10
|
+
* so it moves as a point, not a rectangle, and a thread whose cell the splice deleted is dropped
|
|
11
|
+
* along with its messages. Both halves matter: a cell's legacy note is cell state and travels with
|
|
12
|
+
* the cell, so a thread left behind would put a note on one cell and its conversation on another,
|
|
13
|
+
* a pairing the writer emits and Excel refuses.
|
|
14
|
+
*/
|
|
15
|
+
shift(axis: 'row' | 'col', start: number, count: number, delta: number): void;
|
|
8
16
|
restore(threads: readonly CommentThread[]): void;
|
|
9
17
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { decodeCellRef, encodeAddress } from './address.js';
|
|
2
2
|
import { commentThreadGuid, commentThreadOffset } from './comment-thread.js';
|
|
3
3
|
import { replaceContents } from './containers.js';
|
|
4
|
+
import { isDeletedSpan, shiftIndex } from './grid-shift.js';
|
|
4
5
|
export class WorksheetComments {
|
|
5
6
|
#sheetName;
|
|
6
7
|
#threads = [];
|
|
@@ -42,6 +43,23 @@ export class WorksheetComments {
|
|
|
42
43
|
const anchor = anchorRef(reference);
|
|
43
44
|
return this.#threads.find((thread) => thread.ref === anchor);
|
|
44
45
|
}
|
|
46
|
+
shift(axis, start, count, delta) {
|
|
47
|
+
const survivors = [];
|
|
48
|
+
for (const thread of this.#threads) {
|
|
49
|
+
const { col, row } = decodeCellRef(thread.ref);
|
|
50
|
+
const line = axis === 'row' ? row : col;
|
|
51
|
+
if (isDeletedSpan(line, line, start, count))
|
|
52
|
+
continue;
|
|
53
|
+
const moved = shiftIndex(line, start, count, delta, axis);
|
|
54
|
+
if (moved === line) {
|
|
55
|
+
survivors.push(thread);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const ref = axis === 'row' ? encodeAddress(col, moved) : encodeAddress(moved, row);
|
|
59
|
+
survivors.push({ ...thread, ref });
|
|
60
|
+
}
|
|
61
|
+
replaceContents(this.#threads, survivors);
|
|
62
|
+
}
|
|
45
63
|
restore(threads) {
|
|
46
64
|
replaceContents(this.#threads, threads);
|
|
47
65
|
}
|
package/dist/core/worksheet.d.ts
CHANGED
|
@@ -15,9 +15,19 @@ import { Row } from './row.ts';
|
|
|
15
15
|
import type { CellStyle, Color, Fill } from './style.ts';
|
|
16
16
|
import { Table, type TableOptions } from './table.ts';
|
|
17
17
|
import type { CellValue } from './value.ts';
|
|
18
|
+
/**
|
|
19
|
+
* Whether a thing Excel can hide is showing: a sheet's tab, or the document window itself.
|
|
20
|
+
*
|
|
21
|
+
* One type for two schema enumerations. `ST_SheetState` and `ST_Visibility` are declared separately
|
|
22
|
+
* in ECMA-376 and carry the same three tokens with the same meanings, and `veryHidden` means the same
|
|
23
|
+
* thing in both: hidden, and not offered in the unhide list.
|
|
24
|
+
*/
|
|
25
|
+
export type Visibility = 'visible' | 'hidden' | 'veryHidden';
|
|
26
|
+
/** Narrow a raw `<sheet state>` or `<workbookView visibility>` token to a known {@link Visibility}. */
|
|
27
|
+
export declare function isVisibility(value: string): value is Visibility;
|
|
18
28
|
export interface WorksheetState {
|
|
19
29
|
/** Sheet visibility, as Excel models it. Defaults to `visible`. */
|
|
20
|
-
readonly state:
|
|
30
|
+
readonly state: Visibility;
|
|
21
31
|
}
|
|
22
32
|
/** Format defaults applied to every row/column that carries no explicit override. */
|
|
23
33
|
export interface WorksheetProperties {
|
|
@@ -574,7 +584,10 @@ export declare class Worksheet {
|
|
|
574
584
|
* never disturbs merges or the columns to its left.
|
|
575
585
|
*
|
|
576
586
|
* `values` is an array indexed by row (index 0 → row 1); a hole or an explicit `undefined` leaves
|
|
577
|
-
* that row untouched, mirroring {@link addRow}'s positional-array shape.
|
|
587
|
+
* that row untouched, mirroring {@link addRow}'s positional-array shape. That is the only shape a
|
|
588
|
+
* column takes: the other {@link RowInput} form addresses columns by their
|
|
589
|
+
* {@link ColumnProperties.key}, and a column's values are indexed by *row*, which carries no key,
|
|
590
|
+
* so there is nothing on this axis for a keyed object to name.
|
|
578
591
|
*/
|
|
579
592
|
addColumn(values: CellValue[]): Cell[];
|
|
580
593
|
/**
|
package/dist/core/worksheet.js
CHANGED
|
@@ -11,12 +11,16 @@ import { clearCoveredValues, masterOf } from './merge.js';
|
|
|
11
11
|
import { PivotTable } from './pivot-table.js';
|
|
12
12
|
import { deriveCredential, } from './protection.js';
|
|
13
13
|
import { Range, rangeFrom } from './range.js';
|
|
14
|
-
import { buildRowCells, rowPlacements } from './row-input.js';
|
|
14
|
+
import { buildRowCells, positionalPlacements, rowPlacements } from './row-input.js';
|
|
15
15
|
import { Row } from './row.js';
|
|
16
|
-
import { Table
|
|
16
|
+
import { Table } from './table.js';
|
|
17
17
|
import { WorksheetComments } from './worksheet-comments.js';
|
|
18
18
|
import { WORKSHEET_MODEL_FACETS } from './worksheet-model.js';
|
|
19
19
|
import { WorksheetPictures } from './worksheet-pictures.js';
|
|
20
|
+
const VISIBILITIES = { visible: true, hidden: true, veryHidden: true };
|
|
21
|
+
export function isVisibility(value) {
|
|
22
|
+
return Object.hasOwn(VISIBILITIES, value);
|
|
23
|
+
}
|
|
20
24
|
export class Worksheet {
|
|
21
25
|
name;
|
|
22
26
|
id;
|
|
@@ -62,6 +66,15 @@ export class Worksheet {
|
|
|
62
66
|
mergeRects: this.#mergeRects,
|
|
63
67
|
tables: this.#tables,
|
|
64
68
|
images: this.#images.anchors,
|
|
69
|
+
dataValidations: this.#dataValidations,
|
|
70
|
+
conditionalFormattings: this.#conditionalFormattings,
|
|
71
|
+
comments: this.#comments,
|
|
72
|
+
autoFilter: {
|
|
73
|
+
get: () => this.#autoFilter,
|
|
74
|
+
set: (next) => {
|
|
75
|
+
this.#autoFilter = next;
|
|
76
|
+
},
|
|
77
|
+
},
|
|
65
78
|
});
|
|
66
79
|
}
|
|
67
80
|
getCell(reference) {
|
|
@@ -151,46 +164,17 @@ export class Worksheet {
|
|
|
151
164
|
}
|
|
152
165
|
}
|
|
153
166
|
addTable(options) {
|
|
154
|
-
const table = new Table(options,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
167
|
+
const table = new Table(options, {
|
|
168
|
+
holdsValue: (row, col) => this.hasCell(row, col) && this.#cellAt(row, col).value != null,
|
|
169
|
+
writeCell: (row, col, value, style) => {
|
|
170
|
+
const cell = this.#cellAt(row, col);
|
|
171
|
+
cell.value = value;
|
|
172
|
+
if (style !== undefined)
|
|
173
|
+
applyCellStyle(cell, style);
|
|
174
|
+
},
|
|
175
|
+
insertRow: (row) => this.spliceRows(row, 0, []),
|
|
176
|
+
});
|
|
160
177
|
this.#tables.push(table);
|
|
161
|
-
if (table.headerRow) {
|
|
162
|
-
const { top, left } = table.region;
|
|
163
|
-
table.columns.forEach((column, index) => {
|
|
164
|
-
const col = left + index;
|
|
165
|
-
if (this.hasCell(top, col) && this.#cellAt(top, col).value != null)
|
|
166
|
-
return;
|
|
167
|
-
this.#cellAt(top, col).value = column.name;
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
if (table.totalsRow) {
|
|
171
|
-
const { left, bottom } = table.region;
|
|
172
|
-
table.columns.forEach((column, index) => {
|
|
173
|
-
const col = left + index;
|
|
174
|
-
if (this.hasCell(bottom, col) && this.#cellAt(bottom, col).value != null)
|
|
175
|
-
return;
|
|
176
|
-
if (column.totalsRowLabel !== undefined) {
|
|
177
|
-
this.#cellAt(bottom, col).value = column.totalsRowLabel;
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
if (column.totalsRowFunction !== undefined) {
|
|
181
|
-
const code = TOTALS_ROW_SUBTOTAL_CODE[column.totalsRowFunction];
|
|
182
|
-
if (code !== undefined) {
|
|
183
|
-
this.#cellAt(bottom, col).value = {
|
|
184
|
-
formula: `SUBTOTAL(${code},${table.name}[${column.name}])`,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
else if (column.totalsRowFunction === 'custom' &&
|
|
188
|
-
column.totalsRowFormula !== undefined) {
|
|
189
|
-
this.#cellAt(bottom, col).value = { formula: column.totalsRowFormula };
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
178
|
return table;
|
|
195
179
|
}
|
|
196
180
|
get tables() {
|
|
@@ -373,15 +357,11 @@ export class Worksheet {
|
|
|
373
357
|
let index = this.columnCount;
|
|
374
358
|
return columns.map((values) => {
|
|
375
359
|
index += 1;
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (value === undefined)
|
|
379
|
-
return;
|
|
380
|
-
const cell = this.#cellAt(i + 1, index);
|
|
360
|
+
return positionalPlacements(values).map(([row, value]) => {
|
|
361
|
+
const cell = this.#cellAt(row, index);
|
|
381
362
|
cell.value = value;
|
|
382
|
-
|
|
363
|
+
return cell;
|
|
383
364
|
});
|
|
384
|
-
return cells;
|
|
385
365
|
});
|
|
386
366
|
}
|
|
387
367
|
get model() {
|