@niicojs/excel 0.2.5 → 0.2.6
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/index.cjs +168 -9
- package/dist/index.d.cts +14 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +168 -9
- package/package.json +1 -1
- package/src/pivot-table.ts +40 -15
- package/src/styles.ts +64 -4
- package/src/workbook.ts +4 -0
package/dist/index.js
CHANGED
|
@@ -1115,6 +1115,129 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1115
1115
|
}
|
|
1116
1116
|
}
|
|
1117
1117
|
|
|
1118
|
+
/**
|
|
1119
|
+
* Excel built-in number format IDs (0-163 are reserved).
|
|
1120
|
+
* These formats don't need to be defined in the numFmts element.
|
|
1121
|
+
*/ const BUILTIN_NUM_FMTS = new Map([
|
|
1122
|
+
[
|
|
1123
|
+
'General',
|
|
1124
|
+
0
|
|
1125
|
+
],
|
|
1126
|
+
[
|
|
1127
|
+
'0',
|
|
1128
|
+
1
|
|
1129
|
+
],
|
|
1130
|
+
[
|
|
1131
|
+
'0.00',
|
|
1132
|
+
2
|
|
1133
|
+
],
|
|
1134
|
+
[
|
|
1135
|
+
'#,##0',
|
|
1136
|
+
3
|
|
1137
|
+
],
|
|
1138
|
+
[
|
|
1139
|
+
'#,##0.00',
|
|
1140
|
+
4
|
|
1141
|
+
],
|
|
1142
|
+
[
|
|
1143
|
+
'0%',
|
|
1144
|
+
9
|
|
1145
|
+
],
|
|
1146
|
+
[
|
|
1147
|
+
'0.00%',
|
|
1148
|
+
10
|
|
1149
|
+
],
|
|
1150
|
+
[
|
|
1151
|
+
'0.00E+00',
|
|
1152
|
+
11
|
|
1153
|
+
],
|
|
1154
|
+
[
|
|
1155
|
+
'# ?/?',
|
|
1156
|
+
12
|
|
1157
|
+
],
|
|
1158
|
+
[
|
|
1159
|
+
'# ??/??',
|
|
1160
|
+
13
|
|
1161
|
+
],
|
|
1162
|
+
[
|
|
1163
|
+
'mm-dd-yy',
|
|
1164
|
+
14
|
|
1165
|
+
],
|
|
1166
|
+
[
|
|
1167
|
+
'd-mmm-yy',
|
|
1168
|
+
15
|
|
1169
|
+
],
|
|
1170
|
+
[
|
|
1171
|
+
'd-mmm',
|
|
1172
|
+
16
|
|
1173
|
+
],
|
|
1174
|
+
[
|
|
1175
|
+
'mmm-yy',
|
|
1176
|
+
17
|
|
1177
|
+
],
|
|
1178
|
+
[
|
|
1179
|
+
'h:mm AM/PM',
|
|
1180
|
+
18
|
|
1181
|
+
],
|
|
1182
|
+
[
|
|
1183
|
+
'h:mm:ss AM/PM',
|
|
1184
|
+
19
|
|
1185
|
+
],
|
|
1186
|
+
[
|
|
1187
|
+
'h:mm',
|
|
1188
|
+
20
|
|
1189
|
+
],
|
|
1190
|
+
[
|
|
1191
|
+
'h:mm:ss',
|
|
1192
|
+
21
|
|
1193
|
+
],
|
|
1194
|
+
[
|
|
1195
|
+
'm/d/yy h:mm',
|
|
1196
|
+
22
|
|
1197
|
+
],
|
|
1198
|
+
[
|
|
1199
|
+
'#,##0 ;(#,##0)',
|
|
1200
|
+
37
|
|
1201
|
+
],
|
|
1202
|
+
[
|
|
1203
|
+
'#,##0 ;[Red](#,##0)',
|
|
1204
|
+
38
|
|
1205
|
+
],
|
|
1206
|
+
[
|
|
1207
|
+
'#,##0.00;(#,##0.00)',
|
|
1208
|
+
39
|
|
1209
|
+
],
|
|
1210
|
+
[
|
|
1211
|
+
'#,##0.00;[Red](#,##0.00)',
|
|
1212
|
+
40
|
|
1213
|
+
],
|
|
1214
|
+
[
|
|
1215
|
+
'mm:ss',
|
|
1216
|
+
45
|
|
1217
|
+
],
|
|
1218
|
+
[
|
|
1219
|
+
'[h]:mm:ss',
|
|
1220
|
+
46
|
|
1221
|
+
],
|
|
1222
|
+
[
|
|
1223
|
+
'mmss.0',
|
|
1224
|
+
47
|
|
1225
|
+
],
|
|
1226
|
+
[
|
|
1227
|
+
'##0.0E+0',
|
|
1228
|
+
48
|
|
1229
|
+
],
|
|
1230
|
+
[
|
|
1231
|
+
'@',
|
|
1232
|
+
49
|
|
1233
|
+
]
|
|
1234
|
+
]);
|
|
1235
|
+
/**
|
|
1236
|
+
* Reverse lookup: built-in format ID -> format code
|
|
1237
|
+
*/ const BUILTIN_NUM_FMT_CODES = new Map(Array.from(BUILTIN_NUM_FMTS.entries()).map(([code, id])=>[
|
|
1238
|
+
id,
|
|
1239
|
+
code
|
|
1240
|
+
]));
|
|
1118
1241
|
/**
|
|
1119
1242
|
* Normalize a color to ARGB format (8 hex chars).
|
|
1120
1243
|
* Accepts: "#RGB", "#RRGGBB", "RGB", "RRGGBB", "AARRGGBB", "#AARRGGBB"
|
|
@@ -1305,7 +1428,8 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1305
1428
|
const font = this._fonts[xf.fontId];
|
|
1306
1429
|
const fill = this._fills[xf.fillId];
|
|
1307
1430
|
const border = this._borders[xf.borderId];
|
|
1308
|
-
|
|
1431
|
+
// Check custom formats first, then fall back to built-in format codes
|
|
1432
|
+
const numFmt = this._numFmts.get(xf.numFmtId) ?? BUILTIN_NUM_FMT_CODES.get(xf.numFmtId);
|
|
1309
1433
|
const style = {};
|
|
1310
1434
|
if (font) {
|
|
1311
1435
|
if (font.bold) style.bold = true;
|
|
@@ -1437,16 +1561,30 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1437
1561
|
return this._borders.length - 1;
|
|
1438
1562
|
}
|
|
1439
1563
|
_findOrCreateNumFmt(format) {
|
|
1440
|
-
// Check
|
|
1564
|
+
// Check built-in formats first (IDs 0-163)
|
|
1565
|
+
const builtinId = BUILTIN_NUM_FMTS.get(format);
|
|
1566
|
+
if (builtinId !== undefined) {
|
|
1567
|
+
return builtinId;
|
|
1568
|
+
}
|
|
1569
|
+
// Check if already exists in custom formats
|
|
1441
1570
|
for (const [id, code] of this._numFmts){
|
|
1442
1571
|
if (code === format) return id;
|
|
1443
1572
|
}
|
|
1444
|
-
// Create new
|
|
1445
|
-
const
|
|
1573
|
+
// Create new custom format (IDs 164+)
|
|
1574
|
+
const existingIds = Array.from(this._numFmts.keys());
|
|
1575
|
+
const id = existingIds.length > 0 ? Math.max(...existingIds) + 1 : 164;
|
|
1446
1576
|
this._numFmts.set(id, format);
|
|
1447
1577
|
return id;
|
|
1448
1578
|
}
|
|
1449
1579
|
/**
|
|
1580
|
+
* Get or create a number format ID for the given format string.
|
|
1581
|
+
* Returns built-in IDs (0-163) for standard formats, or creates custom IDs (164+).
|
|
1582
|
+
* @param format - The number format string (e.g., '0.00', '#,##0', '$#,##0.00')
|
|
1583
|
+
*/ getOrCreateNumFmtId(format) {
|
|
1584
|
+
this._dirty = true;
|
|
1585
|
+
return this._findOrCreateNumFmt(format);
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1450
1588
|
* Check if styles have been modified
|
|
1451
1589
|
*/ get dirty() {
|
|
1452
1590
|
return this._dirty;
|
|
@@ -1626,6 +1764,7 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1626
1764
|
this._columnFields = [];
|
|
1627
1765
|
this._valueFields = [];
|
|
1628
1766
|
this._filterFields = [];
|
|
1767
|
+
this._styles = null;
|
|
1629
1768
|
this._name = name;
|
|
1630
1769
|
this._cache = cache;
|
|
1631
1770
|
this._targetSheet = targetSheet;
|
|
@@ -1660,6 +1799,13 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1660
1799
|
return this._pivotTableIndex;
|
|
1661
1800
|
}
|
|
1662
1801
|
/**
|
|
1802
|
+
* Set the styles reference for number format resolution
|
|
1803
|
+
* @internal
|
|
1804
|
+
*/ setStyles(styles) {
|
|
1805
|
+
this._styles = styles;
|
|
1806
|
+
return this;
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1663
1809
|
* Add a field to the row area
|
|
1664
1810
|
* @param fieldName - Name of the source field (column header)
|
|
1665
1811
|
*/ addRowField(fieldName) {
|
|
@@ -1694,7 +1840,8 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1694
1840
|
* @param fieldName - Name of the source field (column header)
|
|
1695
1841
|
* @param aggregation - Aggregation function (sum, count, average, min, max)
|
|
1696
1842
|
* @param displayName - Optional display name (defaults to "Sum of FieldName")
|
|
1697
|
-
|
|
1843
|
+
* @param numberFormat - Optional number format (e.g., '$#,##0.00', '0.00%')
|
|
1844
|
+
*/ addValueField(fieldName, aggregation = 'sum', displayName, numberFormat) {
|
|
1698
1845
|
const fieldIndex = this._cache.getFieldIndex(fieldName);
|
|
1699
1846
|
if (fieldIndex < 0) {
|
|
1700
1847
|
throw new Error(`Field not found in source data: ${fieldName}`);
|
|
@@ -1705,7 +1852,8 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1705
1852
|
fieldIndex,
|
|
1706
1853
|
axis: 'value',
|
|
1707
1854
|
aggregation,
|
|
1708
|
-
displayName: displayName || defaultName
|
|
1855
|
+
displayName: displayName || defaultName,
|
|
1856
|
+
numberFormat
|
|
1709
1857
|
});
|
|
1710
1858
|
return this;
|
|
1711
1859
|
}
|
|
@@ -1828,17 +1976,26 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1828
1976
|
}
|
|
1829
1977
|
// Data fields (values)
|
|
1830
1978
|
if (this._valueFields.length > 0) {
|
|
1831
|
-
const dataFieldNodes = this._valueFields.map((f)=>
|
|
1979
|
+
const dataFieldNodes = this._valueFields.map((f)=>{
|
|
1980
|
+
const attrs = {
|
|
1832
1981
|
name: f.displayName || f.fieldName,
|
|
1833
1982
|
fld: String(f.fieldIndex),
|
|
1834
1983
|
baseField: '0',
|
|
1835
1984
|
baseItem: '0',
|
|
1836
1985
|
subtotal: f.aggregation || 'sum'
|
|
1837
|
-
}
|
|
1986
|
+
};
|
|
1987
|
+
// Add numFmtId if format specified and styles available
|
|
1988
|
+
if (f.numberFormat && this._styles) {
|
|
1989
|
+
attrs.numFmtId = String(this._styles.getOrCreateNumFmtId(f.numberFormat));
|
|
1990
|
+
}
|
|
1991
|
+
return createElement('dataField', attrs, []);
|
|
1992
|
+
});
|
|
1838
1993
|
children.push(createElement('dataFields', {
|
|
1839
1994
|
count: String(dataFieldNodes.length)
|
|
1840
1995
|
}, dataFieldNodes));
|
|
1841
1996
|
}
|
|
1997
|
+
// Check if any value field has a number format
|
|
1998
|
+
const hasNumberFormats = this._valueFields.some((f)=>f.numberFormat);
|
|
1842
1999
|
// Pivot table style
|
|
1843
2000
|
children.push(createElement('pivotTableStyleInfo', {
|
|
1844
2001
|
name: 'PivotStyleMedium9',
|
|
@@ -1853,7 +2010,7 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
1853
2010
|
'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
|
|
1854
2011
|
name: this._name,
|
|
1855
2012
|
cacheId: String(this._cache.cacheId),
|
|
1856
|
-
applyNumberFormats: '0',
|
|
2013
|
+
applyNumberFormats: hasNumberFormats ? '1' : '0',
|
|
1857
2014
|
applyBorderFormats: '0',
|
|
1858
2015
|
applyFontFormats: '0',
|
|
1859
2016
|
applyPatternFormats: '0',
|
|
@@ -2787,6 +2944,8 @@ const builder = new XMLBuilder(builderOptions);
|
|
|
2787
2944
|
// Create pivot table
|
|
2788
2945
|
const pivotTableIndex = this._pivotTables.length + 1;
|
|
2789
2946
|
const pivotTable = new PivotTable(config.name, cache, targetSheet, targetCell, targetAddr.row + 1, targetAddr.col, pivotTableIndex);
|
|
2947
|
+
// Set styles reference for number format resolution
|
|
2948
|
+
pivotTable.setStyles(this._styles);
|
|
2790
2949
|
this._pivotTables.push(pivotTable);
|
|
2791
2950
|
return pivotTable;
|
|
2792
2951
|
}
|
package/package.json
CHANGED
package/src/pivot-table.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AggregationType, PivotFieldAxis } from './types';
|
|
2
|
+
import type { Styles } from './styles';
|
|
2
3
|
import { PivotCache } from './pivot-cache';
|
|
3
4
|
import { createElement, stringifyXml, XmlNode } from './utils/xml';
|
|
4
5
|
|
|
@@ -11,6 +12,7 @@ interface FieldAssignment {
|
|
|
11
12
|
axis: PivotFieldAxis;
|
|
12
13
|
aggregation?: AggregationType;
|
|
13
14
|
displayName?: string;
|
|
15
|
+
numberFormat?: string;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -30,6 +32,7 @@ export class PivotTable {
|
|
|
30
32
|
private _filterFields: FieldAssignment[] = [];
|
|
31
33
|
|
|
32
34
|
private _pivotTableIndex: number;
|
|
35
|
+
private _styles: Styles | null = null;
|
|
33
36
|
|
|
34
37
|
constructor(
|
|
35
38
|
name: string,
|
|
@@ -84,6 +87,15 @@ export class PivotTable {
|
|
|
84
87
|
return this._pivotTableIndex;
|
|
85
88
|
}
|
|
86
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Set the styles reference for number format resolution
|
|
92
|
+
* @internal
|
|
93
|
+
*/
|
|
94
|
+
setStyles(styles: Styles): this {
|
|
95
|
+
this._styles = styles;
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
|
|
87
99
|
/**
|
|
88
100
|
* Add a field to the row area
|
|
89
101
|
* @param fieldName - Name of the source field (column header)
|
|
@@ -127,8 +139,14 @@ export class PivotTable {
|
|
|
127
139
|
* @param fieldName - Name of the source field (column header)
|
|
128
140
|
* @param aggregation - Aggregation function (sum, count, average, min, max)
|
|
129
141
|
* @param displayName - Optional display name (defaults to "Sum of FieldName")
|
|
142
|
+
* @param numberFormat - Optional number format (e.g., '$#,##0.00', '0.00%')
|
|
130
143
|
*/
|
|
131
|
-
addValueField(
|
|
144
|
+
addValueField(
|
|
145
|
+
fieldName: string,
|
|
146
|
+
aggregation: AggregationType = 'sum',
|
|
147
|
+
displayName?: string,
|
|
148
|
+
numberFormat?: string,
|
|
149
|
+
): this {
|
|
132
150
|
const fieldIndex = this._cache.getFieldIndex(fieldName);
|
|
133
151
|
if (fieldIndex < 0) {
|
|
134
152
|
throw new Error(`Field not found in source data: ${fieldName}`);
|
|
@@ -142,6 +160,7 @@ export class PivotTable {
|
|
|
142
160
|
axis: 'value',
|
|
143
161
|
aggregation,
|
|
144
162
|
displayName: displayName || defaultName,
|
|
163
|
+
numberFormat,
|
|
145
164
|
});
|
|
146
165
|
|
|
147
166
|
return this;
|
|
@@ -251,22 +270,28 @@ export class PivotTable {
|
|
|
251
270
|
|
|
252
271
|
// Data fields (values)
|
|
253
272
|
if (this._valueFields.length > 0) {
|
|
254
|
-
const dataFieldNodes = this._valueFields.map((f) =>
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
273
|
+
const dataFieldNodes = this._valueFields.map((f) => {
|
|
274
|
+
const attrs: Record<string, string> = {
|
|
275
|
+
name: f.displayName || f.fieldName,
|
|
276
|
+
fld: String(f.fieldIndex),
|
|
277
|
+
baseField: '0',
|
|
278
|
+
baseItem: '0',
|
|
279
|
+
subtotal: f.aggregation || 'sum',
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// Add numFmtId if format specified and styles available
|
|
283
|
+
if (f.numberFormat && this._styles) {
|
|
284
|
+
attrs.numFmtId = String(this._styles.getOrCreateNumFmtId(f.numberFormat));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return createElement('dataField', attrs, []);
|
|
288
|
+
});
|
|
267
289
|
children.push(createElement('dataFields', { count: String(dataFieldNodes.length) }, dataFieldNodes));
|
|
268
290
|
}
|
|
269
291
|
|
|
292
|
+
// Check if any value field has a number format
|
|
293
|
+
const hasNumberFormats = this._valueFields.some((f) => f.numberFormat);
|
|
294
|
+
|
|
270
295
|
// Pivot table style
|
|
271
296
|
children.push(
|
|
272
297
|
createElement(
|
|
@@ -290,7 +315,7 @@ export class PivotTable {
|
|
|
290
315
|
'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
|
|
291
316
|
name: this._name,
|
|
292
317
|
cacheId: String(this._cache.cacheId),
|
|
293
|
-
applyNumberFormats: '0',
|
|
318
|
+
applyNumberFormats: hasNumberFormats ? '1' : '0',
|
|
294
319
|
applyBorderFormats: '0',
|
|
295
320
|
applyFontFormats: '0',
|
|
296
321
|
applyPatternFormats: '0',
|
package/src/styles.ts
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
import type { CellStyle, BorderType } from './types';
|
|
2
2
|
import { parseXml, findElement, getChildren, getAttr, XmlNode, stringifyXml, createElement } from './utils/xml';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Excel built-in number format IDs (0-163 are reserved).
|
|
6
|
+
* These formats don't need to be defined in the numFmts element.
|
|
7
|
+
*/
|
|
8
|
+
const BUILTIN_NUM_FMTS: Map<string, number> = new Map([
|
|
9
|
+
['General', 0],
|
|
10
|
+
['0', 1],
|
|
11
|
+
['0.00', 2],
|
|
12
|
+
['#,##0', 3],
|
|
13
|
+
['#,##0.00', 4],
|
|
14
|
+
['0%', 9],
|
|
15
|
+
['0.00%', 10],
|
|
16
|
+
['0.00E+00', 11],
|
|
17
|
+
['# ?/?', 12],
|
|
18
|
+
['# ??/??', 13],
|
|
19
|
+
['mm-dd-yy', 14],
|
|
20
|
+
['d-mmm-yy', 15],
|
|
21
|
+
['d-mmm', 16],
|
|
22
|
+
['mmm-yy', 17],
|
|
23
|
+
['h:mm AM/PM', 18],
|
|
24
|
+
['h:mm:ss AM/PM', 19],
|
|
25
|
+
['h:mm', 20],
|
|
26
|
+
['h:mm:ss', 21],
|
|
27
|
+
['m/d/yy h:mm', 22],
|
|
28
|
+
['#,##0 ;(#,##0)', 37],
|
|
29
|
+
['#,##0 ;[Red](#,##0)', 38],
|
|
30
|
+
['#,##0.00;(#,##0.00)', 39],
|
|
31
|
+
['#,##0.00;[Red](#,##0.00)', 40],
|
|
32
|
+
['mm:ss', 45],
|
|
33
|
+
['[h]:mm:ss', 46],
|
|
34
|
+
['mmss.0', 47],
|
|
35
|
+
['##0.0E+0', 48],
|
|
36
|
+
['@', 49],
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Reverse lookup: built-in format ID -> format code
|
|
41
|
+
*/
|
|
42
|
+
const BUILTIN_NUM_FMT_CODES: Map<number, string> = new Map(
|
|
43
|
+
Array.from(BUILTIN_NUM_FMTS.entries()).map(([code, id]) => [id, code]),
|
|
44
|
+
);
|
|
45
|
+
|
|
4
46
|
/**
|
|
5
47
|
* Normalize a color to ARGB format (8 hex chars).
|
|
6
48
|
* Accepts: "#RGB", "#RRGGBB", "RGB", "RRGGBB", "AARRGGBB", "#AARRGGBB"
|
|
@@ -234,7 +276,8 @@ export class Styles {
|
|
|
234
276
|
const font = this._fonts[xf.fontId];
|
|
235
277
|
const fill = this._fills[xf.fillId];
|
|
236
278
|
const border = this._borders[xf.borderId];
|
|
237
|
-
|
|
279
|
+
// Check custom formats first, then fall back to built-in format codes
|
|
280
|
+
const numFmt = this._numFmts.get(xf.numFmtId) ?? BUILTIN_NUM_FMT_CODES.get(xf.numFmtId);
|
|
238
281
|
|
|
239
282
|
const style: CellStyle = {};
|
|
240
283
|
|
|
@@ -403,17 +446,34 @@ export class Styles {
|
|
|
403
446
|
}
|
|
404
447
|
|
|
405
448
|
private _findOrCreateNumFmt(format: string): number {
|
|
406
|
-
// Check
|
|
449
|
+
// Check built-in formats first (IDs 0-163)
|
|
450
|
+
const builtinId = BUILTIN_NUM_FMTS.get(format);
|
|
451
|
+
if (builtinId !== undefined) {
|
|
452
|
+
return builtinId;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Check if already exists in custom formats
|
|
407
456
|
for (const [id, code] of this._numFmts) {
|
|
408
457
|
if (code === format) return id;
|
|
409
458
|
}
|
|
410
459
|
|
|
411
|
-
// Create new
|
|
412
|
-
const
|
|
460
|
+
// Create new custom format (IDs 164+)
|
|
461
|
+
const existingIds = Array.from(this._numFmts.keys());
|
|
462
|
+
const id = existingIds.length > 0 ? Math.max(...existingIds) + 1 : 164;
|
|
413
463
|
this._numFmts.set(id, format);
|
|
414
464
|
return id;
|
|
415
465
|
}
|
|
416
466
|
|
|
467
|
+
/**
|
|
468
|
+
* Get or create a number format ID for the given format string.
|
|
469
|
+
* Returns built-in IDs (0-163) for standard formats, or creates custom IDs (164+).
|
|
470
|
+
* @param format - The number format string (e.g., '0.00', '#,##0', '$#,##0.00')
|
|
471
|
+
*/
|
|
472
|
+
getOrCreateNumFmtId(format: string): number {
|
|
473
|
+
this._dirty = true;
|
|
474
|
+
return this._findOrCreateNumFmt(format);
|
|
475
|
+
}
|
|
476
|
+
|
|
417
477
|
/**
|
|
418
478
|
* Check if styles have been modified
|
|
419
479
|
*/
|
package/src/workbook.ts
CHANGED