@cj-tech-master/excelts 4.0.4-canary.20260109050555.4f97ebb → 4.0.4-canary.20260110000241.8ac37ef

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.
Files changed (55) hide show
  1. package/dist/browser/modules/excel/cell.js +39 -1
  2. package/dist/browser/modules/excel/enums.d.ts +2 -1
  3. package/dist/browser/modules/excel/enums.js +2 -1
  4. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +1 -0
  5. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +19 -1
  6. package/dist/browser/modules/excel/types.d.ts +5 -1
  7. package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +2 -0
  8. package/dist/browser/modules/excel/utils/ooxml-paths.js +4 -2
  9. package/dist/browser/modules/excel/xlsx/rel-type.d.ts +1 -0
  10. package/dist/browser/modules/excel/xlsx/rel-type.js +2 -1
  11. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +7 -0
  12. package/dist/browser/modules/excel/xlsx/xform/core/feature-property-bag-xform.d.ts +8 -0
  13. package/dist/browser/modules/excel/xlsx/xform/core/feature-property-bag-xform.js +36 -0
  14. package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.js +5 -0
  15. package/dist/browser/modules/excel/xlsx/xform/style/style-xform.d.ts +2 -0
  16. package/dist/browser/modules/excel/xlsx/xform/style/style-xform.js +11 -0
  17. package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.d.ts +2 -0
  18. package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.js +28 -4
  19. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +2 -0
  20. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +19 -0
  21. package/dist/cjs/modules/excel/cell.js +39 -1
  22. package/dist/cjs/modules/excel/enums.js +2 -1
  23. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +19 -1
  24. package/dist/cjs/modules/excel/utils/ooxml-paths.js +4 -2
  25. package/dist/cjs/modules/excel/xlsx/rel-type.js +2 -1
  26. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +7 -0
  27. package/dist/cjs/modules/excel/xlsx/xform/core/feature-property-bag-xform.js +39 -0
  28. package/dist/cjs/modules/excel/xlsx/xform/sheet/cell-xform.js +5 -0
  29. package/dist/cjs/modules/excel/xlsx/xform/style/style-xform.js +11 -0
  30. package/dist/cjs/modules/excel/xlsx/xform/style/styles-xform.js +28 -4
  31. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +19 -0
  32. package/dist/esm/modules/excel/cell.js +39 -1
  33. package/dist/esm/modules/excel/enums.js +2 -1
  34. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +19 -1
  35. package/dist/esm/modules/excel/utils/ooxml-paths.js +4 -2
  36. package/dist/esm/modules/excel/xlsx/rel-type.js +2 -1
  37. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +7 -0
  38. package/dist/esm/modules/excel/xlsx/xform/core/feature-property-bag-xform.js +36 -0
  39. package/dist/esm/modules/excel/xlsx/xform/sheet/cell-xform.js +5 -0
  40. package/dist/esm/modules/excel/xlsx/xform/style/style-xform.js +11 -0
  41. package/dist/esm/modules/excel/xlsx/xform/style/styles-xform.js +28 -4
  42. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +19 -0
  43. package/dist/iife/excelts.iife.js +145 -8
  44. package/dist/iife/excelts.iife.js.map +1 -1
  45. package/dist/iife/excelts.iife.min.js +28 -28
  46. package/dist/types/modules/excel/enums.d.ts +2 -1
  47. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +1 -0
  48. package/dist/types/modules/excel/types.d.ts +5 -1
  49. package/dist/types/modules/excel/utils/ooxml-paths.d.ts +2 -0
  50. package/dist/types/modules/excel/xlsx/rel-type.d.ts +1 -0
  51. package/dist/types/modules/excel/xlsx/xform/core/feature-property-bag-xform.d.ts +8 -0
  52. package/dist/types/modules/excel/xlsx/xform/style/style-xform.d.ts +2 -0
  53. package/dist/types/modules/excel/xlsx/xform/style/styles-xform.d.ts +2 -0
  54. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +2 -0
  55. package/package.json +1 -1
@@ -809,6 +809,40 @@ class BooleanValue {
809
809
  return this.model.value.toString();
810
810
  }
811
811
  }
812
+ class CheckboxValue {
813
+ constructor(cell, value) {
814
+ this.model = {
815
+ address: cell.address,
816
+ type: Cell.Types.Checkbox,
817
+ value: value.checkbox
818
+ };
819
+ }
820
+ get value() {
821
+ return { checkbox: this.model.value };
822
+ }
823
+ set value(value) {
824
+ this.model.value = value.checkbox;
825
+ }
826
+ get type() {
827
+ return Cell.Types.Checkbox;
828
+ }
829
+ get effectiveType() {
830
+ return Cell.Types.Boolean;
831
+ }
832
+ get address() {
833
+ return this.model.address;
834
+ }
835
+ set address(value) {
836
+ this.model.address = value;
837
+ }
838
+ toCsvString() {
839
+ return this.model.value ? 1 : 0;
840
+ }
841
+ release() { }
842
+ toString() {
843
+ return this.model.value.toString();
844
+ }
845
+ }
812
846
  class ErrorValue {
813
847
  constructor(cell, value) {
814
848
  this.model = {
@@ -898,6 +932,9 @@ const Value = {
898
932
  return Cell.Types.Date;
899
933
  }
900
934
  if (typeof value === "object") {
935
+ if ("checkbox" in value && typeof value.checkbox === "boolean") {
936
+ return Cell.Types.Checkbox;
937
+ }
901
938
  if ("text" in value && value.text && "hyperlink" in value && value.hyperlink) {
902
939
  return Cell.Types.Hyperlink;
903
940
  }
@@ -930,7 +967,8 @@ const Value = {
930
967
  { t: Cell.Types.SharedString, f: SharedStringValue },
931
968
  { t: Cell.Types.RichText, f: RichTextValue },
932
969
  { t: Cell.Types.Boolean, f: BooleanValue },
933
- { t: Cell.Types.Error, f: ErrorValue }
970
+ { t: Cell.Types.Error, f: ErrorValue },
971
+ { t: Cell.Types.Checkbox, f: CheckboxValue }
934
972
  ].reduce((p, t) => {
935
973
  p[t.t] = t.f;
936
974
  return p;
@@ -10,7 +10,8 @@ export declare enum ValueType {
10
10
  RichText = 8,
11
11
  Boolean = 9,
12
12
  Error = 10,
13
- JSON = 11
13
+ JSON = 11,// Internal type for JSON values that serialize as String
14
+ Checkbox = 12
14
15
  }
15
16
  export declare enum FormulaType {
16
17
  None = 0,
@@ -11,7 +11,8 @@ export var ValueType;
11
11
  ValueType[ValueType["RichText"] = 8] = "RichText";
12
12
  ValueType[ValueType["Boolean"] = 9] = "Boolean";
13
13
  ValueType[ValueType["Error"] = 10] = "Error";
14
- ValueType[ValueType["JSON"] = 11] = "JSON"; // Internal type for JSON values that serialize as String
14
+ ValueType[ValueType["JSON"] = 11] = "JSON";
15
+ ValueType[ValueType["Checkbox"] = 12] = "Checkbox";
15
16
  })(ValueType || (ValueType = {}));
16
17
  export var FormulaType;
17
18
  (function (FormulaType) {
@@ -132,6 +132,7 @@ export declare abstract class WorkbookWriterBase<TWorksheetWriter extends Worksh
132
132
  addApp(): Promise<void>;
133
133
  addCore(): Promise<void>;
134
134
  addSharedStrings(): Promise<void>;
135
+ addFeaturePropertyBag(): Promise<void>;
135
136
  addWorkbookRels(): Promise<void>;
136
137
  addWorkbook(): Promise<void>;
137
138
  _finalize(): Promise<this>;
@@ -20,6 +20,7 @@ import { ContentTypesXform } from "../xlsx/xform/core/content-types-xform.js";
20
20
  import { AppXform } from "../xlsx/xform/core/app-xform.js";
21
21
  import { WorkbookXform } from "../xlsx/xform/book/workbook-xform.js";
22
22
  import { SharedStringsXform } from "../xlsx/xform/strings/shared-strings-xform.js";
23
+ import { FeaturePropertyBagXform } from "../xlsx/xform/core/feature-property-bag-xform.js";
23
24
  import { theme1Xml } from "../xlsx/xml/theme1.js";
24
25
  import { Writeable, stringToUint8Array } from "../../stream/index.browser.js";
25
26
  import { mediaPath, OOXML_PATHS, OOXML_REL_TARGETS, worksheetRelTarget } from "../utils/ooxml-paths.js";
@@ -134,6 +135,7 @@ export class WorkbookWriterBase {
134
135
  this.addCore(),
135
136
  this.addSharedStrings(),
136
137
  this.addStyles(),
138
+ this.addFeaturePropertyBag(),
137
139
  this.addWorkbookRels()
138
140
  ]);
139
141
  await this.addWorkbook();
@@ -226,7 +228,8 @@ export class WorkbookWriterBase {
226
228
  worksheets: this._worksheets.filter(Boolean),
227
229
  sharedStrings: this.sharedStrings,
228
230
  commentRefs: this.commentRefs,
229
- media: this.media
231
+ media: this.media,
232
+ hasCheckboxes: this.styles.hasCheckboxes
230
233
  };
231
234
  const xform = new ContentTypesXform();
232
235
  this._addFile(xform.toXml(model), OOXML_PATHS.contentTypes);
@@ -280,6 +283,13 @@ export class WorkbookWriterBase {
280
283
  }
281
284
  return Promise.resolve();
282
285
  }
286
+ addFeaturePropertyBag() {
287
+ if (this.styles.hasCheckboxes) {
288
+ const xform = new FeaturePropertyBagXform();
289
+ this._addFile(xform.toXml({}), OOXML_PATHS.xlFeaturePropertyBag);
290
+ }
291
+ return Promise.resolve();
292
+ }
283
293
  addWorkbookRels() {
284
294
  let count = 1;
285
295
  const relationships = [
@@ -293,6 +303,14 @@ export class WorkbookWriterBase {
293
303
  Target: OOXML_REL_TARGETS.workbookSharedStrings
294
304
  });
295
305
  }
306
+ // Add FeaturePropertyBag relationship if checkboxes are used
307
+ if (this.styles.hasCheckboxes) {
308
+ relationships.push({
309
+ Id: `rId${count++}`,
310
+ Type: RelType.FeaturePropertyBag,
311
+ Target: OOXML_REL_TARGETS.workbookFeaturePropertyBag
312
+ });
313
+ }
296
314
  this._worksheets.forEach(ws => {
297
315
  if (ws) {
298
316
  ws.rId = `rId${count++}`;
@@ -274,7 +274,11 @@ export interface CellSharedFormulaValue {
274
274
  result?: number | string | boolean | Date | CellErrorValue;
275
275
  date1904?: boolean;
276
276
  }
277
- export type CellValue = null | number | string | boolean | Date | undefined | CellErrorValue | CellRichTextValue | CellHyperlinkValue | CellFormulaValue | CellArrayFormulaValue | CellSharedFormulaValue;
277
+ export interface CellCheckboxValue {
278
+ /** Indicates this is a checkbox value */
279
+ checkbox: boolean;
280
+ }
281
+ export type CellValue = null | number | string | boolean | Date | undefined | CellErrorValue | CellRichTextValue | CellHyperlinkValue | CellFormulaValue | CellArrayFormulaValue | CellSharedFormulaValue | CellCheckboxValue;
278
282
  export interface CommentMargins {
279
283
  insetmode: "auto" | "custom";
280
284
  inset: number[];
@@ -8,6 +8,7 @@ export declare const OOXML_PATHS: {
8
8
  readonly xlSharedStrings: "xl/sharedStrings.xml";
9
9
  readonly xlStyles: "xl/styles.xml";
10
10
  readonly xlTheme1: "xl/theme/theme1.xml";
11
+ readonly xlFeaturePropertyBag: "xl/featurePropertyBag/featurePropertyBag.xml";
11
12
  };
12
13
  export declare function normalizeZipPath(path: string): string;
13
14
  export declare function getWorksheetNoFromWorksheetPath(path: string): number | undefined;
@@ -50,6 +51,7 @@ export declare const OOXML_REL_TARGETS: {
50
51
  readonly workbookStyles: "styles.xml";
51
52
  readonly workbookSharedStrings: "sharedStrings.xml";
52
53
  readonly workbookTheme1: "theme/theme1.xml";
54
+ readonly workbookFeaturePropertyBag: "featurePropertyBag/featurePropertyBag.xml";
53
55
  };
54
56
  export declare function pivotCacheDefinitionRelTargetFromWorkbook(n: number | string): string;
55
57
  export declare function commentsRelTargetFromWorksheet(sheetId: number | string): string;
@@ -7,7 +7,8 @@ export const OOXML_PATHS = {
7
7
  xlWorkbookRels: "xl/_rels/workbook.xml.rels",
8
8
  xlSharedStrings: "xl/sharedStrings.xml",
9
9
  xlStyles: "xl/styles.xml",
10
- xlTheme1: "xl/theme/theme1.xml"
10
+ xlTheme1: "xl/theme/theme1.xml",
11
+ xlFeaturePropertyBag: "xl/featurePropertyBag/featurePropertyBag.xml"
11
12
  };
12
13
  const worksheetXmlRegex = /^xl\/worksheets\/sheet(\d+)[.]xml$/;
13
14
  const worksheetRelsXmlRegex = /^xl\/worksheets\/_rels\/sheet(\d+)[.]xml[.]rels$/;
@@ -162,7 +163,8 @@ export const OOXML_REL_TARGETS = {
162
163
  // Targets inside xl/_rels/workbook.xml.rels (base: xl/)
163
164
  workbookStyles: "styles.xml",
164
165
  workbookSharedStrings: "sharedStrings.xml",
165
- workbookTheme1: "theme/theme1.xml"
166
+ workbookTheme1: "theme/theme1.xml",
167
+ workbookFeaturePropertyBag: "featurePropertyBag/featurePropertyBag.xml"
166
168
  };
167
169
  export function pivotCacheDefinitionRelTargetFromWorkbook(n) {
168
170
  // Target inside xl/_rels/workbook.xml.rels (base: xl/)
@@ -15,5 +15,6 @@ declare const RelType: {
15
15
  PivotCacheDefinition: string;
16
16
  PivotCacheRecords: string;
17
17
  PivotTable: string;
18
+ FeaturePropertyBag: string;
18
19
  };
19
20
  export { RelType };
@@ -14,6 +14,7 @@ const RelType = {
14
14
  Table: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
15
15
  PivotCacheDefinition: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition",
16
16
  PivotCacheRecords: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheRecords",
17
- PivotTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
17
+ PivotTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable",
18
+ FeaturePropertyBag: "http://schemas.microsoft.com/office/2022/11/relationships/FeaturePropertyBag"
18
19
  };
19
20
  export { RelType };
@@ -63,6 +63,13 @@ class ContentTypesXform extends BaseXform {
63
63
  PartName: toContentTypesPartName(OOXML_PATHS.xlStyles),
64
64
  ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"
65
65
  });
66
+ // Add FeaturePropertyBag if checkboxes are used
67
+ if (model.hasCheckboxes) {
68
+ xmlStream.leafNode("Override", {
69
+ PartName: toContentTypesPartName(OOXML_PATHS.xlFeaturePropertyBag),
70
+ ContentType: "application/vnd.ms-excel.featurepropertybag+xml"
71
+ });
72
+ }
66
73
  const hasSharedStrings = model.sharedStrings && model.sharedStrings.count;
67
74
  if (hasSharedStrings) {
68
75
  xmlStream.leafNode("Override", {
@@ -0,0 +1,8 @@
1
+ import { BaseXform } from "@excel/xlsx/xform/base-xform";
2
+ declare class FeaturePropertyBagXform extends BaseXform {
3
+ render(xmlStream: any): void;
4
+ parseOpen(): boolean;
5
+ parseText(): void;
6
+ parseClose(): boolean;
7
+ }
8
+ export { FeaturePropertyBagXform };
@@ -0,0 +1,36 @@
1
+ import { BaseXform } from "../base-xform.js";
2
+ // FeaturePropertyBag is used to enable checkbox functionality
3
+ // This is a static XML file that MS Excel requires for checkboxes to work
4
+ class FeaturePropertyBagXform extends BaseXform {
5
+ render(xmlStream) {
6
+ xmlStream.openXml({ version: "1.0", encoding: "UTF-8", standalone: "yes" });
7
+ xmlStream.openNode("FeaturePropertyBags", {
8
+ xmlns: "http://schemas.microsoft.com/office/spreadsheetml/2022/featurepropertybag"
9
+ });
10
+ // Checkbox feature
11
+ xmlStream.leafNode("bag", { type: "Checkbox" });
12
+ // XFControls bag
13
+ xmlStream.openNode("bag", { type: "XFControls" });
14
+ xmlStream.leafNode("bagId", { k: "CellControl" }, "0");
15
+ xmlStream.closeNode();
16
+ // XFComplement bag
17
+ xmlStream.openNode("bag", { type: "XFComplement" });
18
+ xmlStream.leafNode("bagId", { k: "XFControls" }, "1");
19
+ xmlStream.closeNode();
20
+ // XFComplements bag
21
+ xmlStream.openNode("bag", { type: "XFComplements", extRef: "XFComplementsMapperExtRef" });
22
+ xmlStream.openNode("a", { k: "MappedFeaturePropertyBags" });
23
+ xmlStream.leafNode("bagId", {}, "2");
24
+ xmlStream.closeNode();
25
+ xmlStream.closeNode();
26
+ xmlStream.closeNode();
27
+ }
28
+ parseOpen() {
29
+ return false;
30
+ }
31
+ parseText() { }
32
+ parseClose() {
33
+ return false;
34
+ }
35
+ }
36
+ export { FeaturePropertyBagXform };
@@ -189,6 +189,11 @@ class CellXform extends BaseXform {
189
189
  xmlStream.addAttribute("t", "b");
190
190
  xmlStream.leafNode("v", null, model.value ? "1" : "0");
191
191
  break;
192
+ case Enums.ValueType.Checkbox:
193
+ // Checkboxes are stored as boolean values
194
+ xmlStream.addAttribute("t", "b");
195
+ xmlStream.leafNode("v", null, model.value ? "1" : "0");
196
+ break;
192
197
  case Enums.ValueType.Error:
193
198
  xmlStream.addAttribute("t", "e");
194
199
  xmlStream.leafNode("v", null, model.value.error);
@@ -9,6 +9,8 @@ interface StyleModel {
9
9
  xfId?: number;
10
10
  alignment?: any;
11
11
  protection?: any;
12
+ checkbox?: boolean;
13
+ xfComplementIndex?: number;
12
14
  }
13
15
  interface StyleOptions {
14
16
  xfId?: boolean;
@@ -52,6 +52,17 @@ class StyleXform extends BaseXform {
52
52
  if (model.protection) {
53
53
  this.map.protection.render(xmlStream, model.protection);
54
54
  }
55
+ // Add checkbox extLst if needed
56
+ if (model.checkbox && model.xfComplementIndex !== undefined) {
57
+ xmlStream.openNode("extLst");
58
+ xmlStream.openNode("ext", {
59
+ "xmlns:xfpb": "http://schemas.microsoft.com/office/spreadsheetml/2022/featurepropertybag",
60
+ uri: "{C7286773-470A-42A8-94C5-96B5CB345126}"
61
+ });
62
+ xmlStream.leafNode("xfpb:xfComplement", { i: model.xfComplementIndex });
63
+ xmlStream.closeNode();
64
+ xmlStream.closeNode();
65
+ }
55
66
  xmlStream.closeNode();
56
67
  }
57
68
  parseOpen(node) {
@@ -11,6 +11,7 @@ interface StylesModel {
11
11
  declare class StylesXform extends BaseXform {
12
12
  private index?;
13
13
  private weakMap?;
14
+ private _hasCheckboxes?;
14
15
  parser: any;
15
16
  static Mock: typeof StylesXform;
16
17
  constructor(initialise?: boolean);
@@ -24,6 +25,7 @@ declare class StylesXform extends BaseXform {
24
25
  getStyleModel(id: number): any;
25
26
  addDxfStyle(style: any): number;
26
27
  getDxfStyle(id: number): any;
28
+ get hasCheckboxes(): boolean;
27
29
  _addStyle(style: any): number;
28
30
  _addNumFmtStr(formatCode: string): number;
29
31
  _addFont(font: any): number;
@@ -82,6 +82,7 @@ class StylesXform extends BaseXform {
82
82
  this._addFill({ type: "pattern", pattern: "none" });
83
83
  this._addFill({ type: "pattern", pattern: "gray125" });
84
84
  this.weakMap = new WeakMap();
85
+ this._hasCheckboxes = false;
85
86
  }
86
87
  render(xmlStream, model) {
87
88
  const renderModel = model || this.model;
@@ -222,12 +223,15 @@ class StylesXform extends BaseXform {
222
223
  // default (zero) font
223
224
  this._addFont({ size: 11, color: { theme: 1 }, name: "Calibri", family: 2, scheme: "minor" });
224
225
  }
225
- // if we have seen this style object before, assume it has the same styleId
226
- if (this.weakMap && this.weakMap.has(model)) {
226
+ const type = cellType || Enums.ValueType.Number;
227
+ // If we have seen this style object before, assume it has the same styleId.
228
+ // Do not cache by object identity for checkbox cells because the styleId must
229
+ // include checkbox-specific extLst, and the same style object may be reused
230
+ // for non-checkbox cells.
231
+ if (type !== Enums.ValueType.Checkbox && this.weakMap && this.weakMap.has(model)) {
227
232
  return this.weakMap.get(model);
228
233
  }
229
234
  const style = {};
230
- const type = cellType || Enums.ValueType.Number;
231
235
  if (model.numFmt) {
232
236
  style.numFmtId = this._addNumFmtStr(model.numFmt);
233
237
  }
@@ -258,8 +262,17 @@ class StylesXform extends BaseXform {
258
262
  if (model.protection) {
259
263
  style.protection = model.protection;
260
264
  }
265
+ if (type === Enums.ValueType.Checkbox) {
266
+ // Checkbox rendering relies on style extensions (extLst) and workbook-level parts.
267
+ // Force applyAlignment="1" (without emitting an <alignment/> node) by providing
268
+ // an empty alignment object when none is specified.
269
+ this._hasCheckboxes = true;
270
+ style.alignment = style.alignment || {};
271
+ style.checkbox = true;
272
+ style.xfComplementIndex = 0;
273
+ }
261
274
  const styleId = this._addStyle(style);
262
- if (this.weakMap) {
275
+ if (type !== Enums.ValueType.Checkbox && this.weakMap) {
263
276
  this.weakMap.set(model, styleId);
264
277
  }
265
278
  return styleId;
@@ -322,6 +335,10 @@ class StylesXform extends BaseXform {
322
335
  getDxfStyle(id) {
323
336
  return this.model.dxfs[id];
324
337
  }
338
+ // Check if workbook uses checkbox feature
339
+ get hasCheckboxes() {
340
+ return !!this._hasCheckboxes;
341
+ }
325
342
  // =========================================================================
326
343
  // Private Interface
327
344
  _addStyle(style) {
@@ -457,12 +474,19 @@ class StylesXformMock extends StylesXform {
457
474
  // the styleId is returned. Note: cellType is used when numFmt not defined
458
475
  addStyleModel(model, cellType) {
459
476
  switch (cellType) {
477
+ case Enums.ValueType.Checkbox:
478
+ // Checkbox rendering relies on style extensions (extLst) and workbook-level parts.
479
+ // The mock style manager intentionally does not build those structures.
480
+ throw new Error("Checkbox cells require styles to be enabled (useStyles: true)");
460
481
  case Enums.ValueType.Date:
461
482
  return this.dateStyleId;
462
483
  default:
463
484
  return 0;
464
485
  }
465
486
  }
487
+ get hasCheckboxes() {
488
+ return false;
489
+ }
466
490
  get dateStyleId() {
467
491
  if (!this._dateStyleId) {
468
492
  const dateStyle = {
@@ -92,6 +92,7 @@ declare class XLSX {
92
92
  PivotCacheDefinition: string;
93
93
  PivotCacheRecords: string;
94
94
  PivotTable: string;
95
+ FeaturePropertyBag: string;
95
96
  };
96
97
  constructor(workbook: Workbook);
97
98
  /**
@@ -195,6 +196,7 @@ declare class XLSX {
195
196
  addThemes(zip: IZipWriter, model: any): Promise<void>;
196
197
  addOfficeRels(zip: IZipWriter, _model: any): Promise<void>;
197
198
  addWorkbookRels(zip: IZipWriter, model: any): Promise<void>;
199
+ addFeaturePropertyBag(zip: IZipWriter, model: any): Promise<void>;
198
200
  addSharedStrings(zip: IZipWriter, model: any): Promise<void>;
199
201
  addStyles(zip: IZipWriter, model: any): Promise<void>;
200
202
  addWorkbook(zip: IZipWriter, model: any): Promise<void>;
@@ -17,6 +17,7 @@ import { ContentTypesXform } from "./xform/core/content-types-xform.js";
17
17
  import { AppXform } from "./xform/core/app-xform.js";
18
18
  import { WorkbookXform } from "./xform/book/workbook-xform.js";
19
19
  import { WorkSheetXform } from "./xform/sheet/worksheet-xform.js";
20
+ import { FeaturePropertyBagXform } from "./xform/core/feature-property-bag-xform.js";
20
21
  import { DrawingXform } from "./xform/drawing/drawing-xform.js";
21
22
  import { TableXform } from "./xform/table/table-xform.js";
22
23
  import { PivotCacheRecordsXform } from "./xform/pivot-table/pivot-cache-records-xform.js";
@@ -203,6 +204,7 @@ class XLSX {
203
204
  this.addTables(zip, model);
204
205
  this.addPivotTables(zip, model);
205
206
  await Promise.all([this.addThemes(zip, model), this.addStyles(zip, model)]);
207
+ await this.addFeaturePropertyBag(zip, model);
206
208
  await this.addMedia(zip, model);
207
209
  await Promise.all([this.addApp(zip, model), this.addCore(zip, model)]);
208
210
  await this.addWorkbook(zip, model);
@@ -971,6 +973,14 @@ class XLSX {
971
973
  Target: OOXML_REL_TARGETS.workbookSharedStrings
972
974
  });
973
975
  }
976
+ // Add FeaturePropertyBag relationship if checkboxes are used
977
+ if (model.hasCheckboxes) {
978
+ relationships.push({
979
+ Id: `rId${count++}`,
980
+ Type: XLSX.RelType.FeaturePropertyBag,
981
+ Target: OOXML_REL_TARGETS.workbookFeaturePropertyBag
982
+ });
983
+ }
974
984
  (model.pivotTables || []).forEach((pivotTable) => {
975
985
  pivotTable.rId = `rId${count++}`;
976
986
  relationships.push({
@@ -992,6 +1002,13 @@ class XLSX {
992
1002
  const xml = xform.toXml(relationships);
993
1003
  zip.append(xml, { name: OOXML_PATHS.xlWorkbookRels });
994
1004
  }
1005
+ async addFeaturePropertyBag(zip, model) {
1006
+ if (!model.hasCheckboxes) {
1007
+ return;
1008
+ }
1009
+ const xform = new FeaturePropertyBagXform();
1010
+ zip.append(xform.toXml({}), { name: OOXML_PATHS.xlFeaturePropertyBag });
1011
+ }
995
1012
  async addSharedStrings(zip, model) {
996
1013
  if (model.sharedStrings && model.sharedStrings.count) {
997
1014
  zip.append(model.sharedStrings.xml, { name: OOXML_PATHS.xlSharedStrings });
@@ -1146,6 +1163,8 @@ class XLSX {
1146
1163
  });
1147
1164
  worksheetXform.prepare(worksheet, worksheetOptions);
1148
1165
  });
1166
+ // ContentTypesXform expects this flag
1167
+ model.hasCheckboxes = model.styles.hasCheckboxes;
1149
1168
  }
1150
1169
  }
1151
1170
  XLSX.RelType = RelType;
@@ -813,6 +813,40 @@ class BooleanValue {
813
813
  return this.model.value.toString();
814
814
  }
815
815
  }
816
+ class CheckboxValue {
817
+ constructor(cell, value) {
818
+ this.model = {
819
+ address: cell.address,
820
+ type: Cell.Types.Checkbox,
821
+ value: value.checkbox
822
+ };
823
+ }
824
+ get value() {
825
+ return { checkbox: this.model.value };
826
+ }
827
+ set value(value) {
828
+ this.model.value = value.checkbox;
829
+ }
830
+ get type() {
831
+ return Cell.Types.Checkbox;
832
+ }
833
+ get effectiveType() {
834
+ return Cell.Types.Boolean;
835
+ }
836
+ get address() {
837
+ return this.model.address;
838
+ }
839
+ set address(value) {
840
+ this.model.address = value;
841
+ }
842
+ toCsvString() {
843
+ return this.model.value ? 1 : 0;
844
+ }
845
+ release() { }
846
+ toString() {
847
+ return this.model.value.toString();
848
+ }
849
+ }
816
850
  class ErrorValue {
817
851
  constructor(cell, value) {
818
852
  this.model = {
@@ -902,6 +936,9 @@ const Value = {
902
936
  return Cell.Types.Date;
903
937
  }
904
938
  if (typeof value === "object") {
939
+ if ("checkbox" in value && typeof value.checkbox === "boolean") {
940
+ return Cell.Types.Checkbox;
941
+ }
905
942
  if ("text" in value && value.text && "hyperlink" in value && value.hyperlink) {
906
943
  return Cell.Types.Hyperlink;
907
944
  }
@@ -934,7 +971,8 @@ const Value = {
934
971
  { t: Cell.Types.SharedString, f: SharedStringValue },
935
972
  { t: Cell.Types.RichText, f: RichTextValue },
936
973
  { t: Cell.Types.Boolean, f: BooleanValue },
937
- { t: Cell.Types.Error, f: ErrorValue }
974
+ { t: Cell.Types.Error, f: ErrorValue },
975
+ { t: Cell.Types.Checkbox, f: CheckboxValue }
938
976
  ].reduce((p, t) => {
939
977
  p[t.t] = t.f;
940
978
  return p;
@@ -14,7 +14,8 @@ var ValueType;
14
14
  ValueType[ValueType["RichText"] = 8] = "RichText";
15
15
  ValueType[ValueType["Boolean"] = 9] = "Boolean";
16
16
  ValueType[ValueType["Error"] = 10] = "Error";
17
- ValueType[ValueType["JSON"] = 11] = "JSON"; // Internal type for JSON values that serialize as String
17
+ ValueType[ValueType["JSON"] = 11] = "JSON";
18
+ ValueType[ValueType["Checkbox"] = 12] = "Checkbox";
18
19
  })(ValueType || (exports.ValueType = ValueType = {}));
19
20
  var FormulaType;
20
21
  (function (FormulaType) {
@@ -23,6 +23,7 @@ const content_types_xform_1 = require("../xlsx/xform/core/content-types-xform.js
23
23
  const app_xform_1 = require("../xlsx/xform/core/app-xform.js");
24
24
  const workbook_xform_1 = require("../xlsx/xform/book/workbook-xform.js");
25
25
  const shared_strings_xform_1 = require("../xlsx/xform/strings/shared-strings-xform.js");
26
+ const feature_property_bag_xform_1 = require("../xlsx/xform/core/feature-property-bag-xform.js");
26
27
  const theme1_1 = require("../xlsx/xml/theme1.js");
27
28
  const _stream_1 = require("../../stream/index.js");
28
29
  const ooxml_paths_1 = require("../utils/ooxml-paths.js");
@@ -137,6 +138,7 @@ class WorkbookWriterBase {
137
138
  this.addCore(),
138
139
  this.addSharedStrings(),
139
140
  this.addStyles(),
141
+ this.addFeaturePropertyBag(),
140
142
  this.addWorkbookRels()
141
143
  ]);
142
144
  await this.addWorkbook();
@@ -229,7 +231,8 @@ class WorkbookWriterBase {
229
231
  worksheets: this._worksheets.filter(Boolean),
230
232
  sharedStrings: this.sharedStrings,
231
233
  commentRefs: this.commentRefs,
232
- media: this.media
234
+ media: this.media,
235
+ hasCheckboxes: this.styles.hasCheckboxes
233
236
  };
234
237
  const xform = new content_types_xform_1.ContentTypesXform();
235
238
  this._addFile(xform.toXml(model), ooxml_paths_1.OOXML_PATHS.contentTypes);
@@ -283,6 +286,13 @@ class WorkbookWriterBase {
283
286
  }
284
287
  return Promise.resolve();
285
288
  }
289
+ addFeaturePropertyBag() {
290
+ if (this.styles.hasCheckboxes) {
291
+ const xform = new feature_property_bag_xform_1.FeaturePropertyBagXform();
292
+ this._addFile(xform.toXml({}), ooxml_paths_1.OOXML_PATHS.xlFeaturePropertyBag);
293
+ }
294
+ return Promise.resolve();
295
+ }
286
296
  addWorkbookRels() {
287
297
  let count = 1;
288
298
  const relationships = [
@@ -296,6 +306,14 @@ class WorkbookWriterBase {
296
306
  Target: ooxml_paths_1.OOXML_REL_TARGETS.workbookSharedStrings
297
307
  });
298
308
  }
309
+ // Add FeaturePropertyBag relationship if checkboxes are used
310
+ if (this.styles.hasCheckboxes) {
311
+ relationships.push({
312
+ Id: `rId${count++}`,
313
+ Type: rel_type_1.RelType.FeaturePropertyBag,
314
+ Target: ooxml_paths_1.OOXML_REL_TARGETS.workbookFeaturePropertyBag
315
+ });
316
+ }
299
317
  this._worksheets.forEach(ws => {
300
318
  if (ws) {
301
319
  ws.rId = `rId${count++}`;
@@ -58,7 +58,8 @@ exports.OOXML_PATHS = {
58
58
  xlWorkbookRels: "xl/_rels/workbook.xml.rels",
59
59
  xlSharedStrings: "xl/sharedStrings.xml",
60
60
  xlStyles: "xl/styles.xml",
61
- xlTheme1: "xl/theme/theme1.xml"
61
+ xlTheme1: "xl/theme/theme1.xml",
62
+ xlFeaturePropertyBag: "xl/featurePropertyBag/featurePropertyBag.xml"
62
63
  };
63
64
  const worksheetXmlRegex = /^xl\/worksheets\/sheet(\d+)[.]xml$/;
64
65
  const worksheetRelsXmlRegex = /^xl\/worksheets\/_rels\/sheet(\d+)[.]xml[.]rels$/;
@@ -213,7 +214,8 @@ exports.OOXML_REL_TARGETS = {
213
214
  // Targets inside xl/_rels/workbook.xml.rels (base: xl/)
214
215
  workbookStyles: "styles.xml",
215
216
  workbookSharedStrings: "sharedStrings.xml",
216
- workbookTheme1: "theme/theme1.xml"
217
+ workbookTheme1: "theme/theme1.xml",
218
+ workbookFeaturePropertyBag: "featurePropertyBag/featurePropertyBag.xml"
217
219
  };
218
220
  function pivotCacheDefinitionRelTargetFromWorkbook(n) {
219
221
  // Target inside xl/_rels/workbook.xml.rels (base: xl/)
@@ -17,6 +17,7 @@ const RelType = {
17
17
  Table: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
18
18
  PivotCacheDefinition: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition",
19
19
  PivotCacheRecords: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheRecords",
20
- PivotTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
20
+ PivotTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable",
21
+ FeaturePropertyBag: "http://schemas.microsoft.com/office/2022/11/relationships/FeaturePropertyBag"
21
22
  };
22
23
  exports.RelType = RelType;
@@ -66,6 +66,13 @@ class ContentTypesXform extends base_xform_1.BaseXform {
66
66
  PartName: (0, ooxml_paths_1.toContentTypesPartName)(ooxml_paths_1.OOXML_PATHS.xlStyles),
67
67
  ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"
68
68
  });
69
+ // Add FeaturePropertyBag if checkboxes are used
70
+ if (model.hasCheckboxes) {
71
+ xmlStream.leafNode("Override", {
72
+ PartName: (0, ooxml_paths_1.toContentTypesPartName)(ooxml_paths_1.OOXML_PATHS.xlFeaturePropertyBag),
73
+ ContentType: "application/vnd.ms-excel.featurepropertybag+xml"
74
+ });
75
+ }
69
76
  const hasSharedStrings = model.sharedStrings && model.sharedStrings.count;
70
77
  if (hasSharedStrings) {
71
78
  xmlStream.leafNode("Override", {