@rowsncolumns/toolkit 24.5.3 → 24.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1307,7 +1307,7 @@ var buildWorksheetXml = function (_a) {
1307
1307
  var sheetFormatPrAttrs = ["defaultRowHeight=\"".concat(defaultRowHeightPt, "\"")];
1308
1308
  if (typeof explicitDefaultColumnWidthPx === "number" &&
1309
1309
  explicitDefaultColumnWidthPx > 0) {
1310
- sheetFormatPrAttrs.push("defaultColWidth=\"".concat(columnPixelToChars(explicitDefaultColumnWidthPx).toFixed(2), "\""));
1310
+ sheetFormatPrAttrs.push("defaultColWidth=\"".concat(columnPixelToChars(explicitDefaultColumnWidthPx), "\""));
1311
1311
  }
1312
1312
  var worksheetXml = "".concat(XML_DECLARATION, "<worksheet xmlns=\"").concat(WORKSHEET_NS, "\" xmlns:r=\"").concat(REL_NS, "\">").concat(sheetPrXml, "<dimension ref=\"").concat(dimension, "\"/>").concat(sheetViews, "<sheetFormatPr ").concat(sheetFormatPrAttrs.join(" "), "/>").concat(columnXml).concat(sheetDataXml).concat(protectionXml).concat(basicFilterXml).concat(mergeXml).concat(conditionalFormattingXml).concat(dataValidationsXml).concat(hyperlinksXml).concat(printSettingsXml).concat(drawingXml).concat(legacyDrawingXml).concat(controlsXml).concat(tablePartsXml).concat(extLstXml, "</worksheet>");
1313
1313
  return {
@@ -2514,8 +2514,11 @@ var buildColumnsXml = function (sheet, bounds) {
2514
2514
  continue;
2515
2515
  var attributes = ["min=\"".concat(columnIndex, "\""), "max=\"".concat(columnIndex, "\"")];
2516
2516
  if (hasExplicitSize) {
2517
+ // Full precision on purpose: the stored value is a multiple of 1/256
2518
+ // (Excel writes e.g. 9.140625), and rounding to two decimals would
2519
+ // break the exact export → import pixel fixed point.
2517
2520
  var width = columnPixelToChars(getColumnWidthPx(sheet, columnIndex - 1));
2518
- attributes.push("width=\"".concat(width.toFixed(2), "\""));
2521
+ attributes.push("width=\"".concat(width, "\""));
2519
2522
  attributes.push("customWidth=\"1\"");
2520
2523
  }
2521
2524
  if (hasHiddenFlag) {
@@ -8,7 +8,9 @@ export declare const createDownloadableFile: (filename: string, urlOrBlob: Blob
8
8
  export declare const toArrayBuffer: (data: ArrayBuffer | Uint8Array) => ArrayBuffer;
9
9
  export declare const charsToPixel: (chars: number) => number;
10
10
  export declare const pixelToCharacters: (px: number) => number;
11
+ /** Stored OOXML column width (padded character units) → rendered pixels. */
11
12
  export declare const columnCharsToPixel: (chars: number) => number;
13
+ /** Rendered pixels → stored OOXML column width (padded character units). */
12
14
  export declare const columnPixelToChars: (pixel: number) => number;
13
15
  /**
14
16
  * Get range from address reference with minimal processing
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AA+B3E,eAAO,MAAM,0BAA0B,GACrC,SAAS,MAAM,GAAG,SAAS,EAC3B,YAAY,aAAa,EACzB,iBAAiB,aAAa,EAC9B,UAAU;IACR,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,KACA,MAAM,GAAG,SA8BX,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAiB5B,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,UAAU,MAAM,EAChB,WAAW,IAAI,GAAG,MAAM,8BAazB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,WAAW,GAAG,UAAU,KAAG,WAO9D,CAAC;AAIF,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,WAAiC,CAAC;AAC5E,eAAO,MAAM,iBAAiB,GAAI,IAAI,MAAM,WAA+B,CAAC;AAoB5E,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,WACrB,CAAC;AAE5B,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,WAClB,CAAC;AAE/B;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;;;;;cAwBpE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAsB/C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAe7C"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAiC3E,eAAO,MAAM,0BAA0B,GACrC,SAAS,MAAM,GAAG,SAAS,EAC3B,YAAY,aAAa,EACzB,iBAAiB,aAAa,EAC9B,UAAU;IACR,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,KACA,MAAM,GAAG,SA8BX,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAiB5B,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,UAAU,MAAM,EAChB,WAAW,IAAI,GAAG,MAAM,8BAazB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,WAAW,GAAG,UAAU,KAAG,WAO9D,CAAC;AAIF,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,WAAiC,CAAC;AAC5E,eAAO,MAAM,iBAAiB,GAAI,IAAI,MAAM,WAA+B,CAAC;AAyB5E,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,WACf,CAAC;AAElC,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,WAG/C,CAAC;AAEF;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;;;;;cAwBpE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAsB/C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAe7C"}
@@ -2,6 +2,7 @@ import { __awaiter, __generator, __read } from "tslib";
2
2
  import { addressToCell, canUseDOM } from "@rowsncolumns/utils";
3
3
  // ---- Formula helpers ----
4
4
  import { alpha2number, number2Alpha } from "@rowsncolumns/utils";
5
+ import { excelColumnWidthToPixels } from "./excel-parser/helpers";
5
6
  var CELL_ADDR_RE = /(?:'[^']+'!?|[^'!\s]+!?)?(\$?[A-Z]+\$?\d+)(?::(\$?[A-Z]+\$?\d+))?/g;
6
7
  var parseAddr = function (addr) {
7
8
  var m = /^(\$?)([A-Z]+)(\$?)(\d+)$/.exec(addr);
@@ -98,22 +99,30 @@ export var pixelToCharacters = function (px) { return Math.floor((72 / 96) * px)
98
99
  // export const pixelToDimension = (chWidth: number) =>
99
100
  // Math.ceil((33.25 / 265) * chWidth);
100
101
  // // const dimensionToPixel = (chWidth: number) => (72 / 30) * chWidth;
101
- // Excel column-width / pixel conversion. Excel's rendered column box
102
- // includes a 5-pixel padding around the MDW (max-digit-width, 7 px for
103
- // Calibri 11), so the default width 8.43 renders at 64 px (8.43 × 7 + 5).
104
- // We keep the +5 padding form so a round-trip pixels → width → pixels is
105
- // an identity for the values Excel itself produces.
102
+ // Excel column-width / pixel conversion (ECMA-376 §18.3.1.13).
106
103
  //
107
- // pixels = floor(widthChars × 7 + 5)
108
- // widthChars = (pixels − 5) / 7
109
- //
110
- // The "pure" ECMA-376 §18.3.1.13 formula omits the 5px padding and gives
111
- // 59 for default-width columns instead of Excel's actual 64.
104
+ // OOXML `<col width>` / `<sheetFormatPr defaultColWidth>` are stored in
105
+ // *padded* character units — Excel writes `px / MDW` (the default 64 px
106
+ // column is stored as 9.140625, not 8.43) and renders it back as
107
+ // `Truncate(((256 × width + Truncate(128 / MDW)) / 256) × MDW)`, which the
108
+ // importer implements in `excelColumnWidthToPixels`. The exporter must be
109
+ // that function's inverse so export → import is a fixed point: storing
110
+ // `trunc(px × 256 / MDW) / 256` (Excel's own 1/256-character quantisation)
111
+ // makes `excelColumnWidthToPixels(columnPixelToChars(px)) === px` for every
112
+ // integer pixel width. Subtracting the 5 px cell padding here (the previous
113
+ // `(px − 5) / 7`) shrank every column by 5 px per export/import cycle once
114
+ // the importer stopped adding it. MDW is 7 px for the Calibri 11 /
115
+ // Aptos Narrow 12 defaults at 96 dpi.
116
+ var EXCEL_MAX_DIGIT_WIDTH_PX = 7;
117
+ /** Stored OOXML column width (padded character units) → rendered pixels. */
112
118
  export var columnCharsToPixel = function (chars) {
113
- return Math.floor(chars * 7 + 5);
119
+ return excelColumnWidthToPixels(chars);
114
120
  };
121
+ /** Rendered pixels → stored OOXML column width (padded character units). */
115
122
  export var columnPixelToChars = function (pixel) {
116
- return Math.max(0, (pixel - 5) / 7);
123
+ if (!Number.isFinite(pixel) || pixel <= 0)
124
+ return 0;
125
+ return Math.trunc((pixel * 256) / EXCEL_MAX_DIGIT_WIDTH_PX) / 256;
117
126
  };
118
127
  /**
119
128
  * Get range from address reference with minimal processing
@@ -967,7 +967,7 @@ const buildWorksheetXml = ({ sheet, rows, sharedStrings, sourceSharedStrings, ce
967
967
  const sheetFormatPrAttrs = [`defaultRowHeight="${defaultRowHeightPt}"`];
968
968
  if (typeof explicitDefaultColumnWidthPx === "number" &&
969
969
  explicitDefaultColumnWidthPx > 0) {
970
- sheetFormatPrAttrs.push(`defaultColWidth="${columnPixelToChars(explicitDefaultColumnWidthPx).toFixed(2)}"`);
970
+ sheetFormatPrAttrs.push(`defaultColWidth="${columnPixelToChars(explicitDefaultColumnWidthPx)}"`);
971
971
  }
972
972
  const worksheetXml = `${XML_DECLARATION}<worksheet xmlns="${WORKSHEET_NS}" xmlns:r="${REL_NS}">${sheetPrXml}<dimension ref="${dimension}"/>${sheetViews}<sheetFormatPr ${sheetFormatPrAttrs.join(" ")}/>${columnXml}${sheetDataXml}${protectionXml}${basicFilterXml}${mergeXml}${conditionalFormattingXml}${dataValidationsXml}${hyperlinksXml}${printSettingsXml}${drawingXml}${legacyDrawingXml}${controlsXml}${tablePartsXml}${extLstXml}</worksheet>`;
973
973
  return {
@@ -2208,8 +2208,11 @@ const buildColumnsXml = (sheet, bounds) => {
2208
2208
  continue;
2209
2209
  const attributes = [`min="${columnIndex}"`, `max="${columnIndex}"`];
2210
2210
  if (hasExplicitSize) {
2211
+ // Full precision on purpose: the stored value is a multiple of 1/256
2212
+ // (Excel writes e.g. 9.140625), and rounding to two decimals would
2213
+ // break the exact export → import pixel fixed point.
2211
2214
  const width = columnPixelToChars(getColumnWidthPx(sheet, columnIndex - 1));
2212
- attributes.push(`width="${width.toFixed(2)}"`);
2215
+ attributes.push(`width="${width}"`);
2213
2216
  attributes.push(`customWidth="1"`);
2214
2217
  }
2215
2218
  if (hasHiddenFlag) {
@@ -8,7 +8,9 @@ export declare const createDownloadableFile: (filename: string, urlOrBlob: Blob
8
8
  export declare const toArrayBuffer: (data: ArrayBuffer | Uint8Array) => ArrayBuffer;
9
9
  export declare const charsToPixel: (chars: number) => number;
10
10
  export declare const pixelToCharacters: (px: number) => number;
11
+ /** Stored OOXML column width (padded character units) → rendered pixels. */
11
12
  export declare const columnCharsToPixel: (chars: number) => number;
13
+ /** Rendered pixels → stored OOXML column width (padded character units). */
12
14
  export declare const columnPixelToChars: (pixel: number) => number;
13
15
  /**
14
16
  * Get range from address reference with minimal processing
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AA+B3E,eAAO,MAAM,0BAA0B,GACrC,SAAS,MAAM,GAAG,SAAS,EAC3B,YAAY,aAAa,EACzB,iBAAiB,aAAa,EAC9B,UAAU;IACR,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,KACA,MAAM,GAAG,SA8BX,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAiB5B,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,UAAU,MAAM,EAChB,WAAW,IAAI,GAAG,MAAM,8BAazB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,WAAW,GAAG,UAAU,KAAG,WAO9D,CAAC;AAIF,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,WAAiC,CAAC;AAC5E,eAAO,MAAM,iBAAiB,GAAI,IAAI,MAAM,WAA+B,CAAC;AAoB5E,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,WACrB,CAAC;AAE5B,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,WAClB,CAAC;AAE/B;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;;;;;cAwBpE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAsB/C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAe7C"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAiC3E,eAAO,MAAM,0BAA0B,GACrC,SAAS,MAAM,GAAG,SAAS,EAC3B,YAAY,aAAa,EACzB,iBAAiB,aAAa,EAC9B,UAAU;IACR,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,KACA,MAAM,GAAG,SA8BX,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,UAAU,MAAM,KACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAiB5B,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,UAAU,MAAM,EAChB,WAAW,IAAI,GAAG,MAAM,8BAazB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,WAAW,GAAG,UAAU,KAAG,WAO9D,CAAC;AAIF,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,WAAiC,CAAC;AAC5E,eAAO,MAAM,iBAAiB,GAAI,IAAI,MAAM,WAA+B,CAAC;AAyB5E,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,WACf,CAAC;AAElC,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,WAG/C,CAAC;AAEF;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS;;;;;cAwBpE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAsB/C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAe7C"}
@@ -1,6 +1,7 @@
1
1
  import { addressToCell, canUseDOM } from "@rowsncolumns/utils";
2
2
  // ---- Formula helpers ----
3
3
  import { alpha2number, number2Alpha } from "@rowsncolumns/utils";
4
+ import { excelColumnWidthToPixels } from "./excel-parser/helpers";
4
5
  const CELL_ADDR_RE = /(?:'[^']+'!?|[^'!\s]+!?)?(\$?[A-Z]+\$?\d+)(?::(\$?[A-Z]+\$?\d+))?/g;
5
6
  const parseAddr = (addr) => {
6
7
  const m = /^(\$?)([A-Z]+)(\$?)(\d+)$/.exec(addr);
@@ -95,19 +96,29 @@ export const pixelToCharacters = (px) => Math.floor((72 / 96) * px);
95
96
  // export const pixelToDimension = (chWidth: number) =>
96
97
  // Math.ceil((33.25 / 265) * chWidth);
97
98
  // // const dimensionToPixel = (chWidth: number) => (72 / 30) * chWidth;
98
- // Excel column-width / pixel conversion. Excel's rendered column box
99
- // includes a 5-pixel padding around the MDW (max-digit-width, 7 px for
100
- // Calibri 11), so the default width 8.43 renders at 64 px (8.43 × 7 + 5).
101
- // We keep the +5 padding form so a round-trip pixels → width → pixels is
102
- // an identity for the values Excel itself produces.
99
+ // Excel column-width / pixel conversion (ECMA-376 §18.3.1.13).
103
100
  //
104
- // pixels = floor(widthChars × 7 + 5)
105
- // widthChars = (pixels − 5) / 7
106
- //
107
- // The "pure" ECMA-376 §18.3.1.13 formula omits the 5px padding and gives
108
- // 59 for default-width columns instead of Excel's actual 64.
109
- export const columnCharsToPixel = (chars) => Math.floor(chars * 7 + 5);
110
- export const columnPixelToChars = (pixel) => Math.max(0, (pixel - 5) / 7);
101
+ // OOXML `<col width>` / `<sheetFormatPr defaultColWidth>` are stored in
102
+ // *padded* character units — Excel writes `px / MDW` (the default 64 px
103
+ // column is stored as 9.140625, not 8.43) and renders it back as
104
+ // `Truncate(((256 × width + Truncate(128 / MDW)) / 256) × MDW)`, which the
105
+ // importer implements in `excelColumnWidthToPixels`. The exporter must be
106
+ // that function's inverse so export → import is a fixed point: storing
107
+ // `trunc(px × 256 / MDW) / 256` (Excel's own 1/256-character quantisation)
108
+ // makes `excelColumnWidthToPixels(columnPixelToChars(px)) === px` for every
109
+ // integer pixel width. Subtracting the 5 px cell padding here (the previous
110
+ // `(px − 5) / 7`) shrank every column by 5 px per export/import cycle once
111
+ // the importer stopped adding it. MDW is 7 px for the Calibri 11 /
112
+ // Aptos Narrow 12 defaults at 96 dpi.
113
+ const EXCEL_MAX_DIGIT_WIDTH_PX = 7;
114
+ /** Stored OOXML column width (padded character units) → rendered pixels. */
115
+ export const columnCharsToPixel = (chars) => excelColumnWidthToPixels(chars);
116
+ /** Rendered pixels → stored OOXML column width (padded character units). */
117
+ export const columnPixelToChars = (pixel) => {
118
+ if (!Number.isFinite(pixel) || pixel <= 0)
119
+ return 0;
120
+ return Math.trunc((pixel * 256) / EXCEL_MAX_DIGIT_WIDTH_PX) / 256;
121
+ };
111
122
  /**
112
123
  * Get range from address reference with minimal processing
113
124
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowsncolumns/toolkit",
3
- "version": "24.5.3",
3
+ "version": "24.5.4",
4
4
  "author": "Vinay M",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "main": "./dist/cjs/index.js",