@cj-tech-master/excelts 4.1.0 → 4.2.0-canary.20260110034516.0919d4d

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 (56) hide show
  1. package/dist/browser/index.browser.d.ts +2 -0
  2. package/dist/browser/index.browser.js +1 -0
  3. package/dist/browser/index.d.ts +2 -0
  4. package/dist/browser/index.js +1 -0
  5. package/dist/browser/modules/excel/form-control.d.ts +157 -0
  6. package/dist/browser/modules/excel/form-control.js +267 -0
  7. package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +2 -0
  8. package/dist/browser/modules/excel/utils/ooxml-paths.js +8 -0
  9. package/dist/browser/modules/excel/worksheet.d.ts +32 -0
  10. package/dist/browser/modules/excel/worksheet.js +44 -1
  11. package/dist/browser/modules/excel/xlsx/rel-type.d.ts +1 -0
  12. package/dist/browser/modules/excel/xlsx/rel-type.js +2 -1
  13. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +17 -1
  14. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +22 -0
  15. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +52 -0
  16. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.d.ts +44 -0
  17. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +181 -0
  18. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +24 -1
  19. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +1 -0
  20. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +24 -5
  21. package/dist/cjs/index.js +3 -1
  22. package/dist/cjs/modules/excel/form-control.js +270 -0
  23. package/dist/cjs/modules/excel/utils/ooxml-paths.js +10 -0
  24. package/dist/cjs/modules/excel/worksheet.js +44 -1
  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 +16 -0
  27. package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +55 -0
  28. package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +184 -0
  29. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +23 -0
  30. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +23 -4
  31. package/dist/esm/index.browser.js +1 -0
  32. package/dist/esm/index.js +1 -0
  33. package/dist/esm/modules/excel/form-control.js +267 -0
  34. package/dist/esm/modules/excel/utils/ooxml-paths.js +8 -0
  35. package/dist/esm/modules/excel/worksheet.js +44 -1
  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 +17 -1
  38. package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +52 -0
  39. package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +181 -0
  40. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +24 -1
  41. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +24 -5
  42. package/dist/iife/THIRD_PARTY_NOTICES.md +112 -0
  43. package/dist/iife/excelts.iife.js +466 -30
  44. package/dist/iife/excelts.iife.js.map +1 -1
  45. package/dist/iife/excelts.iife.min.js +30 -30
  46. package/dist/types/index.browser.d.ts +2 -0
  47. package/dist/types/index.d.ts +2 -0
  48. package/dist/types/modules/excel/form-control.d.ts +157 -0
  49. package/dist/types/modules/excel/utils/ooxml-paths.d.ts +2 -0
  50. package/dist/types/modules/excel/worksheet.d.ts +32 -0
  51. package/dist/types/modules/excel/xlsx/rel-type.d.ts +1 -0
  52. package/dist/types/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +22 -0
  53. package/dist/types/modules/excel/xlsx/xform/drawing/vml-drawing-xform.d.ts +44 -0
  54. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +1 -0
  55. package/package.json +2 -2
  56. /package/dist/{LICENSE → iife/LICENSE} +0 -0
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @cj-tech-master/excelts v4.1.0
2
+ * @cj-tech-master/excelts v4.2.0-canary.20260110034516.0919d4d
3
3
  * TypeScript Excel Workbook Manager - Read and Write xlsx and csv Files.
4
4
  * (c) 2026 cjnoname
5
5
  * Released under the MIT License
@@ -2677,6 +2677,228 @@ var ExcelTS = (function(exports) {
2677
2677
  }
2678
2678
  };
2679
2679
 
2680
+ //#endregion
2681
+ //#region src/modules/excel/form-control.ts
2682
+ /**
2683
+ * Form Control Checkbox - Legacy checkbox control compatible with Office 2007+ and WPS/LibreOffice
2684
+ *
2685
+ * Unlike the modern In-Cell Checkbox (which only works in Microsoft 365),
2686
+ * Form Control Checkboxes are floating controls that work in virtually all
2687
+ * spreadsheet applications.
2688
+ */
2689
+ /** EMU (English Metric Units) to pixels conversion factor at 96 DPI */
2690
+ const EMU_PER_PIXEL = 9525;
2691
+ /** EMU to points conversion factor */
2692
+ const EMU_PER_POINT = 12700;
2693
+ /** Default column offset in EMUs (~15 pixels) */
2694
+ const DEFAULT_COL_OFF = 142875;
2695
+ /** Default row offset in EMUs (~3 pixels) */
2696
+ const DEFAULT_ROW_OFF = 28575;
2697
+ /** Default end column offset in EMUs (~29 pixels) */
2698
+ const DEFAULT_END_COL_OFF = 276225;
2699
+ /** Default end row offset in EMUs (~20 pixels) */
2700
+ const DEFAULT_END_ROW_OFF = 190500;
2701
+ var FormCheckbox = class FormCheckbox {
2702
+ constructor(worksheet, range$1, options) {
2703
+ this.worksheet = worksheet;
2704
+ const { tl, br } = this._parseRange(range$1);
2705
+ const shapeId = 1025 + (worksheet.formControls?.length || 0);
2706
+ let link;
2707
+ if (options?.link) link = this._toAbsoluteRef(options.link);
2708
+ this.model = {
2709
+ shapeId,
2710
+ ctrlPropId: 0,
2711
+ tl,
2712
+ br,
2713
+ link,
2714
+ checked: options?.checked ? "Checked" : "Unchecked",
2715
+ text: options?.text ?? "",
2716
+ noThreeD: options?.noThreeD ?? true,
2717
+ print: options?.print ?? false
2718
+ };
2719
+ }
2720
+ /**
2721
+ * Get the checked state
2722
+ */
2723
+ get checked() {
2724
+ return this.model.checked === "Checked";
2725
+ }
2726
+ /**
2727
+ * Set the checked state
2728
+ */
2729
+ set checked(value) {
2730
+ this.model.checked = value ? "Checked" : "Unchecked";
2731
+ }
2732
+ /**
2733
+ * Get the linked cell address
2734
+ */
2735
+ get link() {
2736
+ return this.model.link;
2737
+ }
2738
+ /**
2739
+ * Set the linked cell address
2740
+ */
2741
+ set link(value) {
2742
+ this.model.link = value ? this._toAbsoluteRef(value) : void 0;
2743
+ }
2744
+ /**
2745
+ * Get the label text
2746
+ */
2747
+ get text() {
2748
+ return this.model.text;
2749
+ }
2750
+ /**
2751
+ * Set the label text
2752
+ */
2753
+ set text(value) {
2754
+ this.model.text = value;
2755
+ }
2756
+ /**
2757
+ * Convert cell reference to absolute format (e.g., "A1" -> "$A$1")
2758
+ */
2759
+ _toAbsoluteRef(ref) {
2760
+ if (ref.includes("$")) return ref;
2761
+ const addr = colCache.decodeAddress(ref);
2762
+ return `$${colCache.n2l(addr.col)}$${addr.row}`;
2763
+ }
2764
+ /**
2765
+ * Parse range input into anchor positions
2766
+ */
2767
+ _parseRange(range$1) {
2768
+ let tl;
2769
+ let br;
2770
+ if (typeof range$1 === "string") {
2771
+ const decoded = colCache.decode(range$1);
2772
+ if ("top" in decoded) {
2773
+ tl = {
2774
+ col: decoded.left - 1,
2775
+ colOff: DEFAULT_COL_OFF,
2776
+ row: decoded.top - 1,
2777
+ rowOff: DEFAULT_ROW_OFF
2778
+ };
2779
+ br = {
2780
+ col: decoded.right - 1,
2781
+ colOff: DEFAULT_END_COL_OFF,
2782
+ row: decoded.bottom - 1,
2783
+ rowOff: DEFAULT_END_ROW_OFF
2784
+ };
2785
+ } else {
2786
+ tl = {
2787
+ col: decoded.col - 1,
2788
+ colOff: DEFAULT_COL_OFF,
2789
+ row: decoded.row - 1,
2790
+ rowOff: DEFAULT_ROW_OFF
2791
+ };
2792
+ br = {
2793
+ col: decoded.col + 1,
2794
+ colOff: DEFAULT_END_COL_OFF,
2795
+ row: decoded.row,
2796
+ rowOff: DEFAULT_END_ROW_OFF
2797
+ };
2798
+ }
2799
+ } else if ("startCol" in range$1) {
2800
+ tl = {
2801
+ col: range$1.startCol,
2802
+ colOff: range$1.startColOff ?? DEFAULT_COL_OFF,
2803
+ row: range$1.startRow,
2804
+ rowOff: range$1.startRowOff ?? DEFAULT_ROW_OFF
2805
+ };
2806
+ br = {
2807
+ col: range$1.endCol,
2808
+ colOff: range$1.endColOff ?? DEFAULT_END_COL_OFF,
2809
+ row: range$1.endRow,
2810
+ rowOff: range$1.endRowOff ?? DEFAULT_END_ROW_OFF
2811
+ };
2812
+ } else {
2813
+ if (typeof range$1.tl === "string") {
2814
+ const decoded = colCache.decodeAddress(range$1.tl);
2815
+ tl = {
2816
+ col: decoded.col - 1,
2817
+ colOff: DEFAULT_COL_OFF,
2818
+ row: decoded.row - 1,
2819
+ rowOff: DEFAULT_ROW_OFF
2820
+ };
2821
+ } else tl = {
2822
+ col: range$1.tl.col,
2823
+ colOff: range$1.tl.colOff ?? DEFAULT_COL_OFF,
2824
+ row: range$1.tl.row,
2825
+ rowOff: range$1.tl.rowOff ?? DEFAULT_ROW_OFF
2826
+ };
2827
+ if (range$1.br) if (typeof range$1.br === "string") {
2828
+ const decoded = colCache.decodeAddress(range$1.br);
2829
+ br = {
2830
+ col: decoded.col - 1,
2831
+ colOff: DEFAULT_END_COL_OFF,
2832
+ row: decoded.row - 1,
2833
+ rowOff: DEFAULT_END_ROW_OFF
2834
+ };
2835
+ } else br = {
2836
+ col: range$1.br.col,
2837
+ colOff: range$1.br.colOff ?? DEFAULT_END_COL_OFF,
2838
+ row: range$1.br.row,
2839
+ rowOff: range$1.br.rowOff ?? DEFAULT_END_ROW_OFF
2840
+ };
2841
+ else br = {
2842
+ col: tl.col + 2,
2843
+ colOff: DEFAULT_END_COL_OFF,
2844
+ row: tl.row + 1,
2845
+ rowOff: DEFAULT_END_ROW_OFF
2846
+ };
2847
+ }
2848
+ return {
2849
+ tl,
2850
+ br
2851
+ };
2852
+ }
2853
+ /**
2854
+ * Convert anchor to VML anchor string format
2855
+ * Format: "fromCol, fromColOff, fromRow, fromRowOff, toCol, toColOff, toRow, toRowOff"
2856
+ * VML uses pixels for offsets
2857
+ */
2858
+ getVmlAnchor() {
2859
+ return FormCheckbox.getVmlAnchor(this.model);
2860
+ }
2861
+ /**
2862
+ * Get VML style string for positioning
2863
+ */
2864
+ getVmlStyle() {
2865
+ return FormCheckbox.getVmlStyle(this.model);
2866
+ }
2867
+ /**
2868
+ * Get the numeric checked value for VML (0, 1, or 2)
2869
+ */
2870
+ getVmlCheckedValue() {
2871
+ return FormCheckbox.getVmlCheckedValue(this.model);
2872
+ }
2873
+ /**
2874
+ * Convert anchor to VML anchor string format from model
2875
+ */
2876
+ static getVmlAnchor(model) {
2877
+ const { tl, br } = model;
2878
+ const tlColOff = Math.round(tl.colOff / EMU_PER_PIXEL);
2879
+ const tlRowOff = Math.round(tl.rowOff / EMU_PER_PIXEL);
2880
+ const brColOff = Math.round(br.colOff / EMU_PER_PIXEL);
2881
+ const brRowOff = Math.round(br.rowOff / EMU_PER_PIXEL);
2882
+ return `${tl.col}, ${tlColOff}, ${tl.row}, ${tlRowOff}, ${br.col}, ${brColOff}, ${br.row}, ${brRowOff}`;
2883
+ }
2884
+ /**
2885
+ * Get VML style string for positioning from model
2886
+ */
2887
+ static getVmlStyle(model) {
2888
+ return `position:absolute;margin-left:${Math.round(model.tl.colOff / EMU_PER_POINT)}pt;margin-top:${Math.round(model.tl.rowOff / EMU_PER_POINT)}pt;width:96pt;height:18pt;z-index:1;visibility:visible`;
2889
+ }
2890
+ /**
2891
+ * Get the numeric checked value for VML from model (0, 1, or 2)
2892
+ */
2893
+ static getVmlCheckedValue(model) {
2894
+ switch (model.checked) {
2895
+ case "Checked": return 1;
2896
+ case "Mixed": return 2;
2897
+ default: return 0;
2898
+ }
2899
+ }
2900
+ };
2901
+
2680
2902
  //#endregion
2681
2903
  //#region src/utils/env.ts
2682
2904
  /**
@@ -5080,6 +5302,7 @@ var ExcelTS = (function(exports) {
5080
5302
  this.tables = {};
5081
5303
  this.pivotTables = [];
5082
5304
  this.conditionalFormattings = [];
5305
+ this.formControls = [];
5083
5306
  }
5084
5307
  get name() {
5085
5308
  return this._name;
@@ -5552,6 +5775,41 @@ var ExcelTS = (function(exports) {
5552
5775
  return image && image.imageId;
5553
5776
  }
5554
5777
  /**
5778
+ * Add a form control checkbox to the worksheet.
5779
+ *
5780
+ * Form control checkboxes are the legacy style that work in Office 2007+,
5781
+ * WPS Office, LibreOffice, and other spreadsheet applications.
5782
+ *
5783
+ * Unlike modern in-cell checkboxes (which only work in Microsoft 365),
5784
+ * form control checkboxes are floating controls positioned over cells.
5785
+ *
5786
+ * @param range - Cell reference (e.g., "B2") or range (e.g., "B2:D3") for positioning
5787
+ * @param options - Checkbox options
5788
+ * @returns The created FormCheckbox instance
5789
+ *
5790
+ * @example
5791
+ * // Simple checkbox at B2
5792
+ * ws.addFormCheckbox("B2");
5793
+ *
5794
+ * // Checkbox with label and linked cell
5795
+ * ws.addFormCheckbox("B2:D3", {
5796
+ * text: "Accept terms",
5797
+ * link: "A2",
5798
+ * checked: false
5799
+ * });
5800
+ */
5801
+ addFormCheckbox(range$1, options) {
5802
+ const checkbox = new FormCheckbox(this, range$1, options);
5803
+ this.formControls.push(checkbox);
5804
+ return checkbox;
5805
+ }
5806
+ /**
5807
+ * Get all form control checkboxes in the worksheet
5808
+ */
5809
+ getFormCheckboxes() {
5810
+ return this.formControls;
5811
+ }
5812
+ /**
5555
5813
  * Protect the worksheet with optional password and options
5556
5814
  */
5557
5815
  async protect(password, options) {
@@ -5634,7 +5892,8 @@ var ExcelTS = (function(exports) {
5634
5892
  sheetProtection: this.sheetProtection,
5635
5893
  tables: Object.values(this.tables).map((table) => table.model),
5636
5894
  pivotTables: this.pivotTables,
5637
- conditionalFormattings: this.conditionalFormattings
5895
+ conditionalFormattings: this.conditionalFormattings,
5896
+ formControls: this.formControls.map((fc) => fc.model)
5638
5897
  };
5639
5898
  model.cols = Column.toModel(this.columns || []);
5640
5899
  const rows = model.rows = [];
@@ -5688,6 +5947,7 @@ var ExcelTS = (function(exports) {
5688
5947
  }, {});
5689
5948
  this.pivotTables = value.pivotTables;
5690
5949
  this.conditionalFormattings = value.conditionalFormattings;
5950
+ this.formControls = [];
5691
5951
  }
5692
5952
  };
5693
5953
 
@@ -9739,6 +9999,12 @@ var ExcelTS = (function(exports) {
9739
9999
  function mediaRelTargetFromRels(filename) {
9740
10000
  return `../media/${filename}`;
9741
10001
  }
10002
+ function ctrlPropPath(id) {
10003
+ return `xl/ctrlProps/ctrlProp${id}.xml`;
10004
+ }
10005
+ function ctrlPropRelTargetFromWorksheet(id) {
10006
+ return `../ctrlProps/ctrlProp${id}.xml`;
10007
+ }
9742
10008
 
9743
10009
  //#endregion
9744
10010
  //#region src/modules/excel/xlsx/xform/core/content-types-xform.ts
@@ -9833,6 +10099,16 @@ var ExcelTS = (function(exports) {
9833
10099
  });
9834
10100
  });
9835
10101
  }
10102
+ if (model.formControlRefs) {
10103
+ if (!model.commentRefs) xmlStream.leafNode("Default", {
10104
+ Extension: "vml",
10105
+ ContentType: "application/vnd.openxmlformats-officedocument.vmlDrawing"
10106
+ });
10107
+ for (const ctrlPropId of model.formControlRefs) xmlStream.leafNode("Override", {
10108
+ PartName: toContentTypesPartName(ctrlPropPath(ctrlPropId)),
10109
+ ContentType: "application/vnd.ms-excel.controlproperties+xml"
10110
+ });
10111
+ }
9836
10112
  xmlStream.leafNode("Override", {
9837
10113
  PartName: toContentTypesPartName(OOXML_PATHS.docPropsCore),
9838
10114
  ContentType: "application/vnd.openxmlformats-package.core-properties+xml"
@@ -10414,7 +10690,8 @@ var ExcelTS = (function(exports) {
10414
10690
  PivotCacheDefinition: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition",
10415
10691
  PivotCacheRecords: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheRecords",
10416
10692
  PivotTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable",
10417
- FeaturePropertyBag: "http://schemas.microsoft.com/office/2022/11/relationships/FeaturePropertyBag"
10693
+ FeaturePropertyBag: "http://schemas.microsoft.com/office/2022/11/relationships/FeaturePropertyBag",
10694
+ CtrlProp: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp"
10418
10695
  };
10419
10696
 
10420
10697
  //#endregion
@@ -13339,6 +13616,23 @@ var ExcelTS = (function(exports) {
13339
13616
  Target: pivotTableRelTargetFromWorksheet(pivotTable.tableNumber)
13340
13617
  });
13341
13618
  });
13619
+ if (model.formControls && model.formControls.length > 0) {
13620
+ if (model.comments.length === 0) rels.push({
13621
+ Id: nextRid(rels),
13622
+ Type: RelType.VmlDrawing,
13623
+ Target: vmlDrawingRelTargetFromWorksheet(model.id)
13624
+ });
13625
+ for (const control of model.formControls) {
13626
+ const globalCtrlPropId = options.formControlRefs.length + 1;
13627
+ control.ctrlPropId = globalCtrlPropId;
13628
+ rels.push({
13629
+ Id: nextRid(rels),
13630
+ Type: RelType.CtrlProp,
13631
+ Target: ctrlPropRelTargetFromWorksheet(globalCtrlPropId)
13632
+ });
13633
+ options.formControlRefs.push(globalCtrlPropId);
13634
+ }
13635
+ }
13342
13636
  this.map.extLst.prepare(model, options);
13343
13637
  }
13344
13638
  render(xmlStream, model) {
@@ -16040,41 +16334,125 @@ var ExcelTS = (function(exports) {
16040
16334
  };
16041
16335
 
16042
16336
  //#endregion
16043
- //#region src/modules/excel/xlsx/xform/comment/vml-notes-xform.ts
16044
- var VmlNotesXform = class VmlNotesXform extends BaseXform {
16337
+ //#region src/modules/excel/xlsx/xform/drawing/vml-drawing-xform.ts
16338
+ var VmlDrawingXform = class VmlDrawingXform extends BaseXform {
16045
16339
  constructor() {
16046
16340
  super();
16047
16341
  this.map = { "v:shape": new VmlShapeXform() };
16048
- this.model = { comments: [] };
16342
+ this.model = {
16343
+ comments: [],
16344
+ formControls: []
16345
+ };
16049
16346
  }
16050
16347
  get tag() {
16051
16348
  return "xml";
16052
16349
  }
16350
+ /**
16351
+ * Render VML drawing containing both notes and form controls
16352
+ */
16053
16353
  render(xmlStream, model) {
16054
16354
  const renderModel = model || this.model;
16355
+ const hasComments = renderModel.comments && renderModel.comments.length > 0;
16356
+ const hasFormControls = renderModel.formControls && renderModel.formControls.length > 0;
16055
16357
  xmlStream.openXml(XmlStream.StdDocAttributes);
16056
- xmlStream.openNode(this.tag, VmlNotesXform.DRAWING_ATTRIBUTES);
16358
+ xmlStream.openNode(this.tag, VmlDrawingXform.DRAWING_ATTRIBUTES);
16057
16359
  xmlStream.openNode("o:shapelayout", { "v:ext": "edit" });
16058
16360
  xmlStream.leafNode("o:idmap", {
16059
16361
  "v:ext": "edit",
16060
16362
  data: 1
16061
16363
  });
16062
16364
  xmlStream.closeNode();
16063
- xmlStream.openNode("v:shapetype", {
16064
- id: "_x0000_t202",
16065
- coordsize: "21600,21600",
16066
- "o:spt": 202,
16067
- path: "m,l,21600r21600,l21600,xe"
16068
- });
16069
- xmlStream.leafNode("v:stroke", { joinstyle: "miter" });
16070
- xmlStream.leafNode("v:path", {
16071
- gradientshapeok: "t",
16072
- "o:connecttype": "rect"
16073
- });
16365
+ if (hasComments) {
16366
+ xmlStream.openNode("v:shapetype", {
16367
+ id: "_x0000_t202",
16368
+ coordsize: "21600,21600",
16369
+ "o:spt": 202,
16370
+ path: "m,l,21600r21600,l21600,xe"
16371
+ });
16372
+ xmlStream.leafNode("v:stroke", { joinstyle: "miter" });
16373
+ xmlStream.leafNode("v:path", {
16374
+ gradientshapeok: "t",
16375
+ "o:connecttype": "rect"
16376
+ });
16377
+ xmlStream.closeNode();
16378
+ }
16379
+ if (hasFormControls) {
16380
+ xmlStream.openNode("v:shapetype", {
16381
+ id: "_x0000_t201",
16382
+ coordsize: "21600,21600",
16383
+ "o:spt": "201",
16384
+ path: "m,l,21600r21600,l21600,xe"
16385
+ });
16386
+ xmlStream.leafNode("v:stroke", { joinstyle: "miter" });
16387
+ xmlStream.leafNode("v:path", {
16388
+ shadowok: "f",
16389
+ "o:extrusionok": "f",
16390
+ strokeok: "f",
16391
+ fillok: "f",
16392
+ "o:connecttype": "rect"
16393
+ });
16394
+ xmlStream.leafNode("o:lock", {
16395
+ "v:ext": "edit",
16396
+ shapetype: "t"
16397
+ });
16398
+ xmlStream.closeNode();
16399
+ }
16400
+ if (hasComments) {
16401
+ const comments = renderModel.comments;
16402
+ for (let i = 0; i < comments.length; i++) this.map["v:shape"].render(xmlStream, comments[i], i);
16403
+ }
16404
+ if (hasFormControls) for (const control of renderModel.formControls) this._renderCheckboxShape(xmlStream, control);
16074
16405
  xmlStream.closeNode();
16075
- renderModel.comments.forEach((item, index) => {
16076
- this.map["v:shape"].render(xmlStream, item, index);
16406
+ }
16407
+ /**
16408
+ * Render a checkbox form control shape
16409
+ */
16410
+ _renderCheckboxShape(xmlStream, control) {
16411
+ const shapeAttrs = {
16412
+ id: `_x0000_s${control.shapeId}`,
16413
+ type: "#_x0000_t201",
16414
+ style: FormCheckbox.getVmlStyle(control),
16415
+ "o:insetmode": "auto",
16416
+ fillcolor: "buttonFace [67]",
16417
+ strokecolor: "windowText [64]",
16418
+ "o:preferrelative": "t",
16419
+ filled: "f",
16420
+ stroked: "f"
16421
+ };
16422
+ xmlStream.openNode("v:shape", shapeAttrs);
16423
+ xmlStream.leafNode("v:fill", { "o:detectmouseclick": "t" });
16424
+ xmlStream.leafNode("o:lock", {
16425
+ "v:ext": "edit",
16426
+ text: "t"
16077
16427
  });
16428
+ if (control.text) {
16429
+ xmlStream.openNode("v:textbox", {
16430
+ style: "mso-direction-alt:auto",
16431
+ "o:singleclick": "t"
16432
+ });
16433
+ xmlStream.openNode("div", { style: "text-align:left" });
16434
+ xmlStream.openNode("font", {
16435
+ face: "Tahoma",
16436
+ size: "160",
16437
+ color: "auto"
16438
+ });
16439
+ xmlStream.writeText(control.text);
16440
+ xmlStream.closeNode();
16441
+ xmlStream.closeNode();
16442
+ xmlStream.closeNode();
16443
+ }
16444
+ xmlStream.openNode("x:ClientData", { ObjectType: "Checkbox" });
16445
+ xmlStream.openNode("x:Anchor");
16446
+ xmlStream.writeText(FormCheckbox.getVmlAnchor(control));
16447
+ xmlStream.closeNode();
16448
+ xmlStream.leafNode("x:PrintObject", void 0, control.print ? "True" : "False");
16449
+ xmlStream.leafNode("x:AutoFill", void 0, "False");
16450
+ xmlStream.leafNode("x:AutoLine", void 0, "False");
16451
+ xmlStream.leafNode("x:TextVAlign", void 0, "Center");
16452
+ if (control.link) xmlStream.leafNode("x:FmlaLink", void 0, control.link);
16453
+ if (control.noThreeD) xmlStream.leafNode("x:NoThreeD");
16454
+ xmlStream.leafNode("x:Checked", void 0, String(FormCheckbox.getVmlCheckedValue(control)));
16455
+ xmlStream.closeNode();
16078
16456
  xmlStream.closeNode();
16079
16457
  }
16080
16458
  parseOpen(node) {
@@ -16085,7 +16463,10 @@ var ExcelTS = (function(exports) {
16085
16463
  switch (node.name) {
16086
16464
  case this.tag:
16087
16465
  this.reset();
16088
- this.model = { comments: [] };
16466
+ this.model = {
16467
+ comments: [],
16468
+ formControls: []
16469
+ };
16089
16470
  break;
16090
16471
  default:
16091
16472
  this.parser = this.map[node.name];
@@ -16110,12 +16491,6 @@ var ExcelTS = (function(exports) {
16110
16491
  default: return true;
16111
16492
  }
16112
16493
  }
16113
- reconcile(model, options) {
16114
- model.anchors.forEach((anchor) => {
16115
- if (anchor.br) this.map["xdr:twoCellAnchor"].reconcile(anchor, options);
16116
- else this.map["xdr:oneCellAnchor"].reconcile(anchor, options);
16117
- });
16118
- }
16119
16494
  static {
16120
16495
  this.DRAWING_ATTRIBUTES = {
16121
16496
  "xmlns:v": "urn:schemas-microsoft-com:vml",
@@ -16125,6 +16500,53 @@ var ExcelTS = (function(exports) {
16125
16500
  }
16126
16501
  };
16127
16502
 
16503
+ //#endregion
16504
+ //#region src/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.ts
16505
+ /**
16506
+ * Control Properties Xform - Generates ctrlProp*.xml for form controls
16507
+ *
16508
+ * Each form control (checkbox, button, etc.) has an associated ctrlProp file
16509
+ * that stores its properties like objectType, checked state, and linked cell.
16510
+ */
16511
+ var CtrlPropXform = class extends BaseXform {
16512
+ get tag() {
16513
+ return "formControlPr";
16514
+ }
16515
+ render(xmlStream, model) {
16516
+ const renderModel = model || this.model;
16517
+ const attrs = {
16518
+ xmlns: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
16519
+ objectType: "CheckBox",
16520
+ checked: renderModel.checked,
16521
+ lockText: "1"
16522
+ };
16523
+ if (renderModel.link) attrs.fmlaLink = renderModel.link;
16524
+ if (renderModel.noThreeD) attrs.noThreeD = "1";
16525
+ xmlStream.openXml({
16526
+ version: "1.0",
16527
+ encoding: "UTF-8",
16528
+ standalone: "yes"
16529
+ });
16530
+ xmlStream.leafNode(this.tag, attrs);
16531
+ }
16532
+ /**
16533
+ * Generate XML string directly (convenience method)
16534
+ * Uses render() internally to ensure consistency
16535
+ */
16536
+ toXml(model) {
16537
+ const xmlStream = new XmlStream();
16538
+ this.render(xmlStream, model);
16539
+ return xmlStream.xml;
16540
+ }
16541
+ parseOpen() {
16542
+ return true;
16543
+ }
16544
+ parseText() {}
16545
+ parseClose() {
16546
+ return false;
16547
+ }
16548
+ };
16549
+
16128
16550
  //#endregion
16129
16551
  //#region src/modules/excel/xlsx/xml/theme1.ts
16130
16552
  const theme1Xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office Theme\"> <a:themeElements> <a:clrScheme name=\"Office\"> <a:dk1> <a:sysClr val=\"windowText\" lastClr=\"000000\"/> </a:dk1> <a:lt1> <a:sysClr val=\"window\" lastClr=\"FFFFFF\"/> </a:lt1> <a:dk2> <a:srgbClr val=\"1F497D\"/> </a:dk2> <a:lt2> <a:srgbClr val=\"EEECE1\"/> </a:lt2> <a:accent1> <a:srgbClr val=\"4F81BD\"/> </a:accent1> <a:accent2> <a:srgbClr val=\"C0504D\"/> </a:accent2> <a:accent3> <a:srgbClr val=\"9BBB59\"/> </a:accent3> <a:accent4> <a:srgbClr val=\"8064A2\"/> </a:accent4> <a:accent5> <a:srgbClr val=\"4BACC6\"/> </a:accent5> <a:accent6> <a:srgbClr val=\"F79646\"/> </a:accent6> <a:hlink> <a:srgbClr val=\"0000FF\"/> </a:hlink> <a:folHlink> <a:srgbClr val=\"800080\"/> </a:folHlink> </a:clrScheme> <a:fontScheme name=\"Office\"> <a:majorFont> <a:latin typeface=\"Cambria\"/> <a:ea typeface=\"\"/> <a:cs typeface=\"\"/> <a:font script=\"Jpan\" typeface=\"MS Pゴシック\"/> <a:font script=\"Hang\" typeface=\"맑은 고딕\"/> <a:font script=\"Hans\" typeface=\"宋体\"/> <a:font script=\"Hant\" typeface=\"新細明體\"/> <a:font script=\"Arab\" typeface=\"Times New Roman\"/> <a:font script=\"Hebr\" typeface=\"Times New Roman\"/> <a:font script=\"Thai\" typeface=\"Tahoma\"/> <a:font script=\"Ethi\" typeface=\"Nyala\"/> <a:font script=\"Beng\" typeface=\"Vrinda\"/> <a:font script=\"Gujr\" typeface=\"Shruti\"/> <a:font script=\"Khmr\" typeface=\"MoolBoran\"/> <a:font script=\"Knda\" typeface=\"Tunga\"/> <a:font script=\"Guru\" typeface=\"Raavi\"/> <a:font script=\"Cans\" typeface=\"Euphemia\"/> <a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/> <a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/> <a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/> <a:font script=\"Thaa\" typeface=\"MV Boli\"/> <a:font script=\"Deva\" typeface=\"Mangal\"/> <a:font script=\"Telu\" typeface=\"Gautami\"/> <a:font script=\"Taml\" typeface=\"Latha\"/> <a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/> <a:font script=\"Orya\" typeface=\"Kalinga\"/> <a:font script=\"Mlym\" typeface=\"Kartika\"/> <a:font script=\"Laoo\" typeface=\"DokChampa\"/> <a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/> <a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/> <a:font script=\"Viet\" typeface=\"Times New Roman\"/> <a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/> <a:font script=\"Geor\" typeface=\"Sylfaen\"/> </a:majorFont> <a:minorFont> <a:latin typeface=\"Calibri\"/> <a:ea typeface=\"\"/> <a:cs typeface=\"\"/> <a:font script=\"Jpan\" typeface=\"MS Pゴシック\"/> <a:font script=\"Hang\" typeface=\"맑은 고딕\"/> <a:font script=\"Hans\" typeface=\"宋体\"/> <a:font script=\"Hant\" typeface=\"新細明體\"/> <a:font script=\"Arab\" typeface=\"Arial\"/> <a:font script=\"Hebr\" typeface=\"Arial\"/> <a:font script=\"Thai\" typeface=\"Tahoma\"/> <a:font script=\"Ethi\" typeface=\"Nyala\"/> <a:font script=\"Beng\" typeface=\"Vrinda\"/> <a:font script=\"Gujr\" typeface=\"Shruti\"/> <a:font script=\"Khmr\" typeface=\"DaunPenh\"/> <a:font script=\"Knda\" typeface=\"Tunga\"/> <a:font script=\"Guru\" typeface=\"Raavi\"/> <a:font script=\"Cans\" typeface=\"Euphemia\"/> <a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/> <a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/> <a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/> <a:font script=\"Thaa\" typeface=\"MV Boli\"/> <a:font script=\"Deva\" typeface=\"Mangal\"/> <a:font script=\"Telu\" typeface=\"Gautami\"/> <a:font script=\"Taml\" typeface=\"Latha\"/> <a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/> <a:font script=\"Orya\" typeface=\"Kalinga\"/> <a:font script=\"Mlym\" typeface=\"Kartika\"/> <a:font script=\"Laoo\" typeface=\"DokChampa\"/> <a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/> <a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/> <a:font script=\"Viet\" typeface=\"Arial\"/> <a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/> <a:font script=\"Geor\" typeface=\"Sylfaen\"/> </a:minorFont> </a:fontScheme> <a:fmtScheme name=\"Office\"> <a:fillStyleLst> <a:solidFill> <a:schemeClr val=\"phClr\"/> </a:solidFill> <a:gradFill rotWithShape=\"1\"> <a:gsLst> <a:gs pos=\"0\"> <a:schemeClr val=\"phClr\"> <a:tint val=\"50000\"/> <a:satMod val=\"300000\"/> </a:schemeClr> </a:gs> <a:gs pos=\"35000\"> <a:schemeClr val=\"phClr\"> <a:tint val=\"37000\"/> <a:satMod val=\"300000\"/> </a:schemeClr> </a:gs> <a:gs pos=\"100000\"> <a:schemeClr val=\"phClr\"> <a:tint val=\"15000\"/> <a:satMod val=\"350000\"/> </a:schemeClr> </a:gs> </a:gsLst> <a:lin ang=\"16200000\" scaled=\"1\"/> </a:gradFill> <a:gradFill rotWithShape=\"1\"> <a:gsLst> <a:gs pos=\"0\"> <a:schemeClr val=\"phClr\"> <a:tint val=\"100000\"/> <a:shade val=\"100000\"/> <a:satMod val=\"130000\"/> </a:schemeClr> </a:gs> <a:gs pos=\"100000\"> <a:schemeClr val=\"phClr\"> <a:tint val=\"50000\"/> <a:shade val=\"100000\"/> <a:satMod val=\"350000\"/> </a:schemeClr> </a:gs> </a:gsLst> <a:lin ang=\"16200000\" scaled=\"0\"/> </a:gradFill> </a:fillStyleLst> <a:lnStyleLst> <a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"> <a:solidFill> <a:schemeClr val=\"phClr\"> <a:shade val=\"95000\"/> <a:satMod val=\"105000\"/> </a:schemeClr> </a:solidFill> <a:prstDash val=\"solid\"/> </a:ln> <a:ln w=\"25400\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"> <a:solidFill> <a:schemeClr val=\"phClr\"/> </a:solidFill> <a:prstDash val=\"solid\"/> </a:ln> <a:ln w=\"38100\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"> <a:solidFill> <a:schemeClr val=\"phClr\"/> </a:solidFill> <a:prstDash val=\"solid\"/> </a:ln> </a:lnStyleLst> <a:effectStyleLst> <a:effectStyle> <a:effectLst> <a:outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\" rotWithShape=\"0\"> <a:srgbClr val=\"000000\"> <a:alpha val=\"38000\"/> </a:srgbClr> </a:outerShdw> </a:effectLst> </a:effectStyle> <a:effectStyle> <a:effectLst> <a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\"> <a:srgbClr val=\"000000\"> <a:alpha val=\"35000\"/> </a:srgbClr> </a:outerShdw> </a:effectLst> </a:effectStyle> <a:effectStyle> <a:effectLst> <a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\"> <a:srgbClr val=\"000000\"> <a:alpha val=\"35000\"/> </a:srgbClr> </a:outerShdw> </a:effectLst> <a:scene3d> <a:camera prst=\"orthographicFront\"> <a:rot lat=\"0\" lon=\"0\" rev=\"0\"/> </a:camera> <a:lightRig rig=\"threePt\" dir=\"t\"> <a:rot lat=\"0\" lon=\"0\" rev=\"1200000\"/> </a:lightRig> </a:scene3d> <a:sp3d> <a:bevelT w=\"63500\" h=\"25400\"/> </a:sp3d> </a:effectStyle> </a:effectStyleLst> <a:bgFillStyleLst> <a:solidFill> <a:schemeClr val=\"phClr\"/> </a:solidFill> <a:gradFill rotWithShape=\"1\"> <a:gsLst> <a:gs pos=\"0\"> <a:schemeClr val=\"phClr\"> <a:tint val=\"40000\"/> <a:satMod val=\"350000\"/> </a:schemeClr> </a:gs> <a:gs pos=\"40000\"> <a:schemeClr val=\"phClr\"> <a:tint val=\"45000\"/> <a:shade val=\"99000\"/> <a:satMod val=\"350000\"/> </a:schemeClr> </a:gs> <a:gs pos=\"100000\"> <a:schemeClr val=\"phClr\"> <a:shade val=\"20000\"/> <a:satMod val=\"255000\"/> </a:schemeClr> </a:gs> </a:gsLst> <a:path path=\"circle\"> <a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/> </a:path> </a:gradFill> <a:gradFill rotWithShape=\"1\"> <a:gsLst> <a:gs pos=\"0\"> <a:schemeClr val=\"phClr\"> <a:tint val=\"80000\"/> <a:satMod val=\"300000\"/> </a:schemeClr> </a:gs> <a:gs pos=\"100000\"> <a:schemeClr val=\"phClr\"> <a:shade val=\"30000\"/> <a:satMod val=\"200000\"/> </a:schemeClr> </a:gs> </a:gsLst> <a:path path=\"circle\"> <a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/> </a:path> </a:gradFill> </a:bgFillStyleLst> </a:fmtScheme> </a:themeElements> <a:objectDefaults> <a:spDef> <a:spPr/> <a:bodyPr/> <a:lstStyle/> <a:style> <a:lnRef idx=\"1\"> <a:schemeClr val=\"accent1\"/> </a:lnRef> <a:fillRef idx=\"3\"> <a:schemeClr val=\"accent1\"/> </a:fillRef> <a:effectRef idx=\"2\"> <a:schemeClr val=\"accent1\"/> </a:effectRef> <a:fontRef idx=\"minor\"> <a:schemeClr val=\"lt1\"/> </a:fontRef> </a:style> </a:spDef> <a:lnDef> <a:spPr/> <a:bodyPr/> <a:lstStyle/> <a:style> <a:lnRef idx=\"2\"> <a:schemeClr val=\"accent1\"/> </a:lnRef> <a:fillRef idx=\"0\"> <a:schemeClr val=\"accent1\"/> </a:fillRef> <a:effectRef idx=\"1\"> <a:schemeClr val=\"accent1\"/> </a:effectRef> <a:fontRef idx=\"minor\"> <a:schemeClr val=\"tx1\"/> </a:fontRef> </a:style> </a:lnDef> </a:objectDefaults> <a:extraClrSchemeLst/> </a:theme>";
@@ -20146,7 +20568,7 @@ var ExcelTS = (function(exports) {
20146
20568
  model.drawingRels[name] = relationships;
20147
20569
  }
20148
20570
  async _processVmlDrawingEntry(entry, model, name) {
20149
- const vmlDrawing = await new VmlNotesXform().parseStream(entry);
20571
+ const vmlDrawing = await new VmlDrawingXform().parseStream(entry);
20150
20572
  model.vmlDrawings[vmlDrawingRelTargetFromWorksheetName(name)] = vmlDrawing;
20151
20573
  }
20152
20574
  async _processThemeEntry(stream, model, name) {
@@ -20437,7 +20859,8 @@ var ExcelTS = (function(exports) {
20437
20859
  const worksheetXform = new WorkSheetXform();
20438
20860
  const relationshipsXform = new RelationshipsXform();
20439
20861
  const commentsXform = new CommentsXform();
20440
- const vmlNotesXform = new VmlNotesXform();
20862
+ const vmlDrawingXform = new VmlDrawingXform();
20863
+ const ctrlPropXform = new CtrlPropXform();
20441
20864
  model.worksheets.forEach((worksheet, index) => {
20442
20865
  const fileIndex = worksheet.fileIndex || index + 1;
20443
20866
  let xmlStream = new XmlStream();
@@ -20452,10 +20875,21 @@ var ExcelTS = (function(exports) {
20452
20875
  xmlStream = new XmlStream();
20453
20876
  commentsXform.render(xmlStream, worksheet);
20454
20877
  zip.append(xmlStream.xml, { name: commentsPath(fileIndex) });
20878
+ }
20879
+ const hasComments = worksheet.comments.length > 0;
20880
+ const hasFormControls = worksheet.formControls && worksheet.formControls.length > 0;
20881
+ if (hasComments || hasFormControls) {
20455
20882
  xmlStream = new XmlStream();
20456
- vmlNotesXform.render(xmlStream, worksheet);
20883
+ vmlDrawingXform.render(xmlStream, {
20884
+ comments: hasComments ? worksheet.comments : [],
20885
+ formControls: hasFormControls ? worksheet.formControls : []
20886
+ });
20457
20887
  zip.append(xmlStream.xml, { name: vmlDrawingPath(fileIndex) });
20458
20888
  }
20889
+ if (hasFormControls) worksheet.formControls.forEach((control) => {
20890
+ const xml = ctrlPropXform.toXml(control);
20891
+ zip.append(xml, { name: ctrlPropPath(control.ctrlPropId) });
20892
+ });
20459
20893
  });
20460
20894
  }
20461
20895
  addDrawings(zip, model) {
@@ -20552,6 +20986,7 @@ var ExcelTS = (function(exports) {
20552
20986
  };
20553
20987
  worksheetOptions.drawings = model.drawings = [];
20554
20988
  worksheetOptions.commentRefs = model.commentRefs = [];
20989
+ worksheetOptions.formControlRefs = model.formControlRefs = [];
20555
20990
  let tableCount = 0;
20556
20991
  model.tables = [];
20557
20992
  model.worksheets.forEach((worksheet) => {
@@ -24789,6 +25224,7 @@ exports.DataValidations = DataValidations;
24789
25224
  exports.DocumentType = DocumentType;
24790
25225
  exports.Enums = Enums;
24791
25226
  exports.ErrorValue = ErrorValue;
25227
+ exports.FormCheckbox = FormCheckbox;
24792
25228
  exports.FormulaType = FormulaType;
24793
25229
  exports.Image = Image;
24794
25230
  exports.PaperSize = PaperSize;