@extend-ai/react-xlsx 0.17.0 → 0.17.2

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 CHANGED
@@ -3632,7 +3632,7 @@ function resolveWorkbookColor(color, themePalette) {
3632
3632
  if (directHex) {
3633
3633
  return normalizeHexColor2(directHex);
3634
3634
  }
3635
- const themeValue = color.theme;
3635
+ const themeValue = color.theme ?? color.themeIndex;
3636
3636
  const numericTheme = typeof themeValue === "number" ? themeValue : typeof themeValue === "string" && themeValue.trim().length > 0 ? Number(themeValue) : Number.NaN;
3637
3637
  const themeColor = Number.isFinite(numericTheme) ? themePalette?.colorsByIndex[numericTheme] ?? null : null;
3638
3638
  if (!themeColor) {
@@ -4260,6 +4260,12 @@ function parseSpreadsheetFont(node) {
4260
4260
  return void 0;
4261
4261
  }
4262
4262
  const font = {};
4263
+ for (const [tag, property] of [["b", "bold"], ["i", "italic"], ["strike", "strikethrough"]]) {
4264
+ const flag = getFirstChild(node, tag);
4265
+ if (flag) {
4266
+ font[property] = hasEnabledSpreadsheetFlag(flag);
4267
+ }
4268
+ }
4263
4269
  const size = getFirstChild(node, "sz")?.getAttribute("val");
4264
4270
  const name = getFirstChild(node, "name")?.getAttribute("val");
4265
4271
  const family = getFirstChild(node, "family")?.getAttribute("val");
@@ -4267,15 +4273,6 @@ function parseSpreadsheetFont(node) {
4267
4273
  const charset = getFirstChild(node, "charset")?.getAttribute("val");
4268
4274
  const verticalAlign = getFirstChild(node, "vertAlign")?.getAttribute("val");
4269
4275
  const color = parseSpreadsheetColor(getFirstChild(node, "color"));
4270
- if (hasEnabledSpreadsheetFlag(getFirstChild(node, "b"))) {
4271
- font.bold = true;
4272
- }
4273
- if (hasEnabledSpreadsheetFlag(getFirstChild(node, "i"))) {
4274
- font.italic = true;
4275
- }
4276
- if (hasEnabledSpreadsheetFlag(getFirstChild(node, "strike"))) {
4277
- font.strikethrough = true;
4278
- }
4279
4276
  if (getFirstChild(node, "u")) {
4280
4277
  font.underline = getFirstChild(node, "u")?.getAttribute("val") ?? "single";
4281
4278
  }
@@ -4524,7 +4521,14 @@ function parseWorkbookStyles(archive) {
4524
4521
  const styleById = {};
4525
4522
  const tableStyleByName = {};
4526
4523
  getChildElements(cellXfsNode, "xf").forEach((xfNode, index) => {
4527
- styleById[index] = parseResolvedXfStyle(xfNode, fonts, fills, borders, checkboxComplementIndices);
4524
+ const style = parseResolvedXfStyle(xfNode, fonts, fills, borders, checkboxComplementIndices);
4525
+ const overrides = {};
4526
+ for (const component of ["font", "fill", "border"]) {
4527
+ if (Number(xfNode.getAttribute(`${component}Id`) ?? 0) > 0 && xfNode.getAttribute(`apply${component[0].toUpperCase()}${component.slice(1)}`) !== "0") {
4528
+ Object.assign(overrides, { [component]: style[component] });
4529
+ }
4530
+ }
4531
+ styleById[index] = { ...style, tableStyleOverrides: overrides };
4528
4532
  });
4529
4533
  getChildElements(cellStylesNode ?? document2.documentElement, "cellStyle").forEach((cellStyleNode) => {
4530
4534
  const name = cellStyleNode.getAttribute("name");
@@ -4868,6 +4872,7 @@ function parseSheetState(archive, path, options) {
4868
4872
  const rowHeightOverridesPx = {};
4869
4873
  const colWidthOverridesPx = {};
4870
4874
  const rowStyleIds = {};
4875
+ const cellStyleIds = {};
4871
4876
  const colStyleIds = {};
4872
4877
  let minContentCol = Number.POSITIVE_INFINITY;
4873
4878
  let minContentRow = Number.POSITIVE_INFINITY;
@@ -4917,6 +4922,10 @@ function parseSheetState(archive, path, options) {
4917
4922
  }
4918
4923
  getChildElements(rowNode, "c").forEach((cellNode) => {
4919
4924
  const cellRef = cellNode.getAttribute("r");
4925
+ const cellStyleId = Number(cellNode.getAttribute("s") ?? Number.NaN);
4926
+ if (cellRef && Number.isFinite(cellStyleId)) {
4927
+ cellStyleIds[cellRef] = cellStyleId;
4928
+ }
4920
4929
  if (isMeaningfulCellNode(cellNode)) {
4921
4930
  trackContentCell(cellRef);
4922
4931
  }
@@ -4955,6 +4964,7 @@ function parseSheetState(archive, path, options) {
4955
4964
  return {
4956
4965
  autoFilterRanges,
4957
4966
  cachedFormulaValues,
4967
+ cellStyleIds,
4958
4968
  columnWidthCharacterWidthPx,
4959
4969
  colWidthOverridesPx,
4960
4970
  colStyleIds,
@@ -6697,13 +6707,52 @@ function hasUnresolvedSheetReferences(workbook) {
6697
6707
  }
6698
6708
  return false;
6699
6709
  }
6710
+ function collectFormulaCellsWithSavedValues(workbook) {
6711
+ const positions = [];
6712
+ for (let sheetIdx = 0; sheetIdx < workbook.sheetCount; sheetIdx += 1) {
6713
+ let sheet;
6714
+ try {
6715
+ sheet = workbook.getSheet(sheetIdx);
6716
+ } catch {
6717
+ continue;
6718
+ }
6719
+ const cells = sheet.formulaCells;
6720
+ if (!Array.isArray(cells)) {
6721
+ continue;
6722
+ }
6723
+ for (const cell of cells) {
6724
+ if (typeof cell?.row !== "number" || typeof cell?.col !== "number") {
6725
+ continue;
6726
+ }
6727
+ let saved;
6728
+ try {
6729
+ saved = sheet.getCalculatedValueAt(cell.row, cell.col);
6730
+ } catch {
6731
+ continue;
6732
+ }
6733
+ if (!saved.is_empty && !saved.is_error) {
6734
+ positions.push({ sheetIdx, row: cell.row, col: cell.col });
6735
+ }
6736
+ }
6737
+ }
6738
+ return positions;
6739
+ }
6740
+ function anyBecameError(workbook, positions) {
6741
+ return positions.some(({ sheetIdx, row, col }) => {
6742
+ try {
6743
+ return workbook.getSheet(sheetIdx).getCalculatedValueAt(row, col).is_error;
6744
+ } catch {
6745
+ return false;
6746
+ }
6747
+ });
6748
+ }
6700
6749
  function safeCalculate(workbook, options = {}) {
6701
6750
  if (hasUnresolvedSheetReferences(workbook)) {
6702
6751
  return { workbook, calculated: false, skipReason: "unresolved-sheet-refs" };
6703
6752
  }
6753
+ const withSavedValues = options.reparse ? collectFormulaCellsWithSavedValues(workbook) : [];
6704
6754
  try {
6705
6755
  workbook.calculate();
6706
- return { workbook, calculated: true, skipReason: null };
6707
6756
  } catch (err) {
6708
6757
  console.warn("[react-xlsx] workbook.calculate() trapped; falling back to cached formula values", err);
6709
6758
  if (options.reparse) {
@@ -6715,6 +6764,14 @@ function safeCalculate(workbook, options = {}) {
6715
6764
  }
6716
6765
  return { workbook, calculated: false, skipReason: "calculate-trapped" };
6717
6766
  }
6767
+ if (options.reparse && anyBecameError(workbook, withSavedValues)) {
6768
+ try {
6769
+ return { workbook: options.reparse(), calculated: false, skipReason: "calculate-regressed" };
6770
+ } catch (reparseErr) {
6771
+ console.warn("[react-xlsx] workbook reparse after calculate regression failed", reparseErr);
6772
+ }
6773
+ }
6774
+ return { workbook, calculated: true, skipReason: null };
6718
6775
  }
6719
6776
  function tryRecalculate(workbook) {
6720
6777
  try {
@@ -7458,6 +7515,7 @@ function buildSheetList(workbook, sheetStatesByWorkbookSheetIndex, themePalette,
7458
7515
  colCount: 0,
7459
7516
  rowHeightOverridesPx: sheetState?.rowHeightOverridesPx ?? {},
7460
7517
  rowStyleIds: sheetState?.rowStyleIds ?? {},
7518
+ cellStyleIds: sheetState?.cellStyleIds ?? {},
7461
7519
  styleById: styleById ?? {},
7462
7520
  sparklines: sheetState?.sparklines ?? [],
7463
7521
  tableStyleByName: tableStyleByName ?? {},
@@ -7544,6 +7602,7 @@ function buildSheetList(workbook, sheetStatesByWorkbookSheetIndex, themePalette,
7544
7602
  namedCellStyleByName: namedCellStyleByName ?? {},
7545
7603
  rowHeightOverridesPx: sheetState?.rowHeightOverridesPx ?? {},
7546
7604
  rowStyleIds: sheetState?.rowStyleIds ?? {},
7605
+ cellStyleIds: sheetState?.cellStyleIds ?? {},
7547
7606
  showGridLines: sheetState?.showGridLines ?? true,
7548
7607
  styleById: styleById ?? {},
7549
7608
  sparklines: sheetState?.sparklines ?? [],
@@ -10007,7 +10066,7 @@ function useXlsxViewerController(options) {
10007
10066
  return;
10008
10067
  }
10009
10068
  const dataStartRow = targetTable.start.row + Math.max(targetTable.headerRowCount, 1);
10010
- const totalsRowOffset = targetTable.totalsRowShown ? Math.max(targetTable.totalsRowCount, 1) : 0;
10069
+ const totalsRowOffset = targetTable.totalsRowCount;
10011
10070
  const dataEndRow = targetTable.end.row - totalsRowOffset;
10012
10071
  const startCol = targetTable.start.col;
10013
10072
  const endCol = targetTable.end.col;
@@ -19171,7 +19230,8 @@ function applyCanvasBorderDash(context, style, width) {
19171
19230
  context.setLineDash([]);
19172
19231
  }
19173
19232
  function strokeCanvasBorderSide(context, side, rect, border) {
19174
- const halfWidth = border.width / 2;
19233
+ const strokeWidth = border.style === "double" ? border.width / 3 : border.width;
19234
+ const halfWidth = strokeWidth / 2;
19175
19235
  const left = rect.left;
19176
19236
  const right = rect.left + rect.width;
19177
19237
  const top = rect.top;
@@ -19197,8 +19257,8 @@ function strokeCanvasBorderSide(context, side, rect, border) {
19197
19257
  context.stroke();
19198
19258
  };
19199
19259
  if (border.style === "double") {
19200
- const inset = Math.max(1, border.width);
19201
- context.lineWidth = Math.max(1, border.width / 3);
19260
+ const inset = border.width - strokeWidth;
19261
+ context.lineWidth = strokeWidth;
19202
19262
  context.setLineDash([]);
19203
19263
  strokeLine(0);
19204
19264
  strokeLine(inset);
@@ -22111,6 +22171,43 @@ function mergeResolvedCellStyle(base, overlay, options) {
22111
22171
  }
22112
22172
  return nextStyle;
22113
22173
  }
22174
+ function resolveCellTableOverrides(rawStyle, sheet, row, col) {
22175
+ const styleId = sheet?.cellStyleIds?.[cellAddressToA12({ row, col })] ?? sheet?.rowStyleIds[row] ?? sheet?.colStyleIds[col];
22176
+ const declared = styleId === void 0 ? void 0 : sheet?.styleById[styleId]?.tableStyleOverrides;
22177
+ const overrides = {};
22178
+ const font = asRecord(rawStyle?.font);
22179
+ if (font) {
22180
+ const explicitFont = {};
22181
+ const fontDefaults = {
22182
+ name: "Calibri",
22183
+ size: 11,
22184
+ bold: false,
22185
+ italic: false,
22186
+ underline: "none",
22187
+ strikethrough: false,
22188
+ verticalAlign: "baseline"
22189
+ };
22190
+ for (const [key, value] of Object.entries(font)) {
22191
+ const isExplicit = declared ? Object.hasOwn(declared.font ?? {}, key) : key === "color" ? asRecord(value)?.colorType !== "auto" : value !== fontDefaults[key];
22192
+ if (isExplicit) {
22193
+ explicitFont[key] = value;
22194
+ }
22195
+ }
22196
+ overrides.font = explicitFont;
22197
+ }
22198
+ const fill = asRecord(rawStyle?.fill);
22199
+ if (fill && fill.fillType !== "none") {
22200
+ overrides.fill = fill;
22201
+ }
22202
+ const border = asRecord(rawStyle?.border);
22203
+ if (border) {
22204
+ overrides.border = Object.fromEntries(Object.entries(border).filter(([, edge]) => {
22205
+ const style = asRecord(edge)?.style;
22206
+ return typeof style === "string" && style !== "none";
22207
+ }));
22208
+ }
22209
+ return overrides;
22210
+ }
22114
22211
  function resolveBorderEdgePriority(edge) {
22115
22212
  const style = typeof edge?.style === "string" ? edge.style : "none";
22116
22213
  const stylePriority = {
@@ -22239,7 +22336,7 @@ function resolveTableCellStyle(table, row, col, activeSheet) {
22239
22336
  return null;
22240
22337
  }
22241
22338
  const headerRowCount = Math.max(table.headerRowCount, 1);
22242
- const totalsRowCount = table.totalsRowShown ? Math.max(table.totalsRowCount, 1) : 0;
22339
+ const totalsRowCount = table.totalsRowCount;
22243
22340
  const headerEndRow = table.start.row + headerRowCount - 1;
22244
22341
  const totalsStartRow = table.end.row - totalsRowCount + 1;
22245
22342
  const bodyStartRow = headerEndRow + 1;
@@ -26563,7 +26660,10 @@ function XlsxGrid({
26563
26660
  });
26564
26661
  const targetTable = getTableAtCell(effectiveTables, targetRow, targetCol);
26565
26662
  const targetTableStyle = resolveTableCellStyle(targetTable, targetRow, targetCol, activeSheet);
26566
- const resolvedStyle = mergeResolvedCellStyle(targetRawStyle, targetTableStyle);
26663
+ const resolvedStyle = targetTableStyle ? mergeResolvedCellStyle(
26664
+ mergeResolvedCellStyle(targetRawStyle, targetTableStyle),
26665
+ resolveCellTableOverrides(targetRawStyle, activeSheet, targetRow, targetCol)
26666
+ ) : targetRawStyle;
26567
26667
  cellBaseRawStyleCacheRef.current.set(targetCacheKey, resolvedStyle);
26568
26668
  return resolvedStyle;
26569
26669
  };
@@ -28934,6 +29034,14 @@ function XlsxGrid({
28934
29034
  hasPendingGridlinePath = false;
28935
29035
  };
28936
29036
  const drawnMergedAnchorKeys = /* @__PURE__ */ new Set();
29037
+ const deferredDoubleBorders = [];
29038
+ const drawCellBorder = (side, rect, border) => {
29039
+ if (border.style === "double") {
29040
+ deferredDoubleBorders.push({ side, rect, border });
29041
+ } else {
29042
+ strokeCanvasBorderSide(paneContext, side, rect, border);
29043
+ }
29044
+ };
28937
29045
  for (const rowItem of paneAxisItems.rows) {
28938
29046
  for (const colItem of paneAxisItems.cols) {
28939
29047
  const cell = { row: rowItem.actualRow, col: colItem.actualCol };
@@ -29080,16 +29188,24 @@ function XlsxGrid({
29080
29188
  flushPendingGridlines();
29081
29189
  }
29082
29190
  if (topBorder && drawRowIndex === 0) {
29083
- strokeCanvasBorderSide(paneContext, "top", localRect, topBorder);
29191
+ drawCellBorder("top", localRect, topBorder);
29084
29192
  }
29085
29193
  if (resolvedRightBorder) {
29086
- strokeCanvasBorderSide(paneContext, "right", localRect, resolvedRightBorder);
29194
+ if (resolvedRightBorder.style === "double" && resolvedRightBorder === rightNeighborLeftBorder) {
29195
+ drawCellBorder("left", { ...localRect, left: localRect.left + localRect.width }, resolvedRightBorder);
29196
+ } else {
29197
+ drawCellBorder("right", localRect, resolvedRightBorder);
29198
+ }
29087
29199
  }
29088
29200
  if (resolvedBottomBorder) {
29089
- strokeCanvasBorderSide(paneContext, "bottom", localRect, resolvedBottomBorder);
29201
+ if (resolvedBottomBorder.style === "double" && resolvedBottomBorder === bottomNeighborTopBorder) {
29202
+ drawCellBorder("top", { ...localRect, top: localRect.top + localRect.height }, resolvedBottomBorder);
29203
+ } else {
29204
+ drawCellBorder("bottom", localRect, resolvedBottomBorder);
29205
+ }
29090
29206
  }
29091
29207
  if (leftBorder && drawColIndex === 0) {
29092
- strokeCanvasBorderSide(paneContext, "left", localRect, leftBorder);
29208
+ drawCellBorder("left", localRect, leftBorder);
29093
29209
  }
29094
29210
  if (cellData.chartHighlight) {
29095
29211
  const highlightBorder = {
@@ -29362,6 +29478,9 @@ function XlsxGrid({
29362
29478
  }
29363
29479
  }
29364
29480
  flushPendingGridlines();
29481
+ for (const { side, rect, border } of deferredDoubleBorders) {
29482
+ strokeCanvasBorderSide(paneContext, side, rect, border);
29483
+ }
29365
29484
  }
29366
29485
  for (const pane of cellPaneOrder) {
29367
29486
  const paneContext = bodyContexts[pane];