@extend-ai/react-xlsx 0.16.2 → 0.16.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.
@@ -2866,6 +2866,17 @@ function applyChartOrigins(chartsByWorkbookSheetIndex2, chartOriginsById, archiv
2866
2866
  });
2867
2867
  }
2868
2868
  }
2869
+ function hydrateWorkbookChartStyles(chartsByWorkbookSheetIndex2, imageAssets) {
2870
+ const chartOriginsById = /* @__PURE__ */ new Map();
2871
+ applyChartOrigins(chartsByWorkbookSheetIndex2, chartOriginsById, imageAssets.archive, imageAssets.sheetOrigins);
2872
+ for (const charts of chartsByWorkbookSheetIndex2) {
2873
+ for (const chart of charts) {
2874
+ applyChartStyleFromXml(chart, chart.chartPath, imageAssets.archive, imageAssets.themePalette);
2875
+ applyBuiltinChartDefaults(chart, imageAssets.themePalette);
2876
+ }
2877
+ }
2878
+ return chartOriginsById;
2879
+ }
2869
2880
  function loadWorkbookChartAssets(workbook2, imageAssets, visibleSheetIndexByWorkbookSheetIndex, showHiddenSheets = false) {
2870
2881
  const excludedChartIds = /* @__PURE__ */ new Set();
2871
2882
  const chartsByWorkbookSheetIndex2 = Array.from({ length: workbook2.sheetCount }, (_, workbookSheetIndex) => {
@@ -2966,21 +2977,14 @@ function loadWorkbookChartAssets(workbook2, imageAssets, visibleSheetIndexByWork
2966
2977
  });
2967
2978
  const chartsheets2 = Array.isArray(workbook2.chartsheets) ? workbook2.chartsheets.map((entry, index) => normalizeChartsheet(entry, index)) : [];
2968
2979
  const tabs2 = buildTabs(workbook2, chartsheets2, visibleSheetIndexByWorkbookSheetIndex, showHiddenSheets);
2969
- const chartOriginsById = /* @__PURE__ */ new Map();
2980
+ const chartOriginsById = imageAssets ? hydrateWorkbookChartStyles(chartsByWorkbookSheetIndex2, imageAssets) : /* @__PURE__ */ new Map();
2970
2981
  if (imageAssets) {
2971
- applyChartOrigins(chartsByWorkbookSheetIndex2, chartOriginsById, imageAssets.archive, imageAssets.sheetOrigins);
2972
2982
  for (let index = 0; index < chartsByWorkbookSheetIndex2.length; index += 1) {
2973
2983
  chartsByWorkbookSheetIndex2[index] = (chartsByWorkbookSheetIndex2[index] ?? []).filter((chart) => !excludedChartIds.has(chart.id));
2974
2984
  }
2975
2985
  for (const id of excludedChartIds) {
2976
2986
  chartOriginsById.delete(id);
2977
2987
  }
2978
- for (const charts of chartsByWorkbookSheetIndex2) {
2979
- for (const chart of charts) {
2980
- applyChartStyleFromXml(chart, chart.chartPath, imageAssets.archive, imageAssets.themePalette);
2981
- applyBuiltinChartDefaults(chart, imageAssets.themePalette);
2982
- }
2983
- }
2984
2988
  } else {
2985
2989
  for (let index = 0; index < chartsByWorkbookSheetIndex2.length; index += 1) {
2986
2990
  chartsByWorkbookSheetIndex2[index] = (chartsByWorkbookSheetIndex2[index] ?? []).filter((chart) => !excludedChartIds.has(chart.id));
@@ -3808,6 +3812,7 @@ function parseWorkbookStyles(archive) {
3808
3812
  const xml = readArchiveText2(archive, "xl/styles.xml");
3809
3813
  if (!xml) {
3810
3814
  return {
3815
+ differentialStyles: [],
3811
3816
  defaultFont: null,
3812
3817
  namedCellStyleByName: {},
3813
3818
  styleById: {},
@@ -3817,6 +3822,7 @@ function parseWorkbookStyles(archive) {
3817
3822
  const document2 = parseXml2(xml);
3818
3823
  if (!document2) {
3819
3824
  return {
3825
+ differentialStyles: [],
3820
3826
  defaultFont: null,
3821
3827
  namedCellStyleByName: {},
3822
3828
  styleById: {},
@@ -3833,6 +3839,7 @@ function parseWorkbookStyles(archive) {
3833
3839
  const tableStylesNode = getFirstDescendant(document2, "tableStyles");
3834
3840
  if (!cellXfsNode) {
3835
3841
  return {
3842
+ differentialStyles: [],
3836
3843
  defaultFont: null,
3837
3844
  namedCellStyleByName: {},
3838
3845
  styleById: {},
@@ -3889,6 +3896,7 @@ function parseWorkbookStyles(archive) {
3889
3896
  sizePt: typeof normalFont.size === "number" ? normalFont.size : void 0
3890
3897
  } : null;
3891
3898
  return {
3899
+ differentialStyles,
3892
3900
  defaultFont,
3893
3901
  namedCellStyleByName,
3894
3902
  styleById,
@@ -3929,10 +3937,11 @@ function parseSpreadsheetBooleanAttribute(node, name) {
3929
3937
  }
3930
3938
  return value !== "0" && value !== "false";
3931
3939
  }
3932
- function parseStandardConditionalFormatRule(cfRuleNode, ranges) {
3940
+ function parseStandardConditionalFormatRule(cfRuleNode, ranges, differentialStyles = []) {
3933
3941
  const type = cfRuleNode.getAttribute("type");
3934
3942
  const rawPriority = Number(cfRuleNode.getAttribute("priority") ?? Number.NaN);
3935
3943
  const priority = Number.isFinite(rawPriority) ? rawPriority : Number.MAX_SAFE_INTEGER;
3944
+ const formulas = getChildElements(cfRuleNode, "formula").map((formulaNode) => (formulaNode.textContent ?? "").trim()).filter((formula) => formula.length > 0);
3936
3945
  if (type === "colorScale") {
3937
3946
  const colorScaleNode = getFirstChild(cfRuleNode, "colorScale");
3938
3947
  if (!colorScaleNode) {
@@ -3993,7 +4002,34 @@ function parseStandardConditionalFormatRule(cfRuleNode, ranges) {
3993
4002
  showValue: parseSpreadsheetBooleanAttribute(iconSetNode, "showValue")
3994
4003
  };
3995
4004
  }
3996
- return null;
4005
+ const rawDxfId = Number(cfRuleNode.getAttribute("dxfId") ?? Number.NaN);
4006
+ if (!type || !Number.isFinite(rawDxfId)) {
4007
+ return null;
4008
+ }
4009
+ const style = differentialStyles[rawDxfId];
4010
+ if (!style) {
4011
+ return null;
4012
+ }
4013
+ const rawRank = Number(cfRuleNode.getAttribute("rank") ?? Number.NaN);
4014
+ const rawStdDev = Number(cfRuleNode.getAttribute("stdDev") ?? Number.NaN);
4015
+ return {
4016
+ aboveAverage: parseSpreadsheetBooleanAttribute(cfRuleNode, "aboveAverage"),
4017
+ bottom: parseSpreadsheetBooleanAttribute(cfRuleNode, "bottom"),
4018
+ equalAverage: parseSpreadsheetBooleanAttribute(cfRuleNode, "equalAverage"),
4019
+ formulas,
4020
+ kind: "styled",
4021
+ operator: cfRuleNode.getAttribute("operator") ?? void 0,
4022
+ percent: parseSpreadsheetBooleanAttribute(cfRuleNode, "percent"),
4023
+ priority,
4024
+ rank: Number.isFinite(rawRank) ? rawRank : void 0,
4025
+ ranges,
4026
+ ruleType: type,
4027
+ stdDev: Number.isFinite(rawStdDev) ? rawStdDev : void 0,
4028
+ stopIfTrue: parseSpreadsheetBooleanAttribute(cfRuleNode, "stopIfTrue"),
4029
+ style,
4030
+ text: cfRuleNode.getAttribute("text") ?? void 0,
4031
+ timePeriod: cfRuleNode.getAttribute("timePeriod") ?? void 0
4032
+ };
3997
4033
  }
3998
4034
  function parseExtendedConditionalFormatRule(cfRuleNode, ranges) {
3999
4035
  const type = cfRuleNode.getAttribute("type");
@@ -4104,14 +4140,14 @@ function mergeConditionalFormatRule(baseRule, extendedRule) {
4104
4140
  }
4105
4141
  return baseRule;
4106
4142
  }
4107
- function parseConditionalFormatRules(document2) {
4143
+ function parseConditionalFormatRules(document2, differentialStyles = []) {
4108
4144
  const standardRules = [];
4109
4145
  const extendedRules = [];
4110
4146
  getLocalElements(document2, "conditionalFormatting").forEach((conditionalFormattingNode) => {
4111
4147
  const isExtended = conditionalFormattingNode.namespaceURI !== SPREADSHEET_NS;
4112
4148
  const ranges = isExtended ? parseSqrefRanges(getFirstChild(conditionalFormattingNode, "sqref")?.textContent ?? "") : parseSqrefRanges(conditionalFormattingNode.getAttribute("sqref"));
4113
4149
  getChildElements(conditionalFormattingNode, "cfRule").forEach((cfRuleNode) => {
4114
- const parsedRule = isExtended ? parseExtendedConditionalFormatRule(cfRuleNode, ranges) : parseStandardConditionalFormatRule(cfRuleNode, ranges);
4150
+ const parsedRule = isExtended ? parseExtendedConditionalFormatRule(cfRuleNode, ranges) : parseStandardConditionalFormatRule(cfRuleNode, ranges, differentialStyles);
4115
4151
  if (parsedRule) {
4116
4152
  if (isExtended) {
4117
4153
  extendedRules.push(parsedRule);
@@ -4157,8 +4193,9 @@ function parseSheetState(archive, path, options) {
4157
4193
  return null;
4158
4194
  }
4159
4195
  const includeCachedFormulaValues = options?.includeCachedFormulaValues ?? true;
4196
+ const autoFilterRanges = parseSqrefRanges(getLocalElements(document2, "autoFilter")[0]?.getAttribute("ref"));
4160
4197
  const cachedFormulaValues = {};
4161
- const conditionalFormatRules = parseConditionalFormatRules(document2);
4198
+ const conditionalFormatRules = parseConditionalFormatRules(document2, options?.differentialStyles ?? []);
4162
4199
  const sparklines = parseSheetSparklines(document2, options?.themePalette);
4163
4200
  const sheetFormatNode = getLocalElements(document2, "sheetFormatPr")[0] ?? null;
4164
4201
  const sheetViewNode = getLocalElements(document2, "sheetView")[0] ?? null;
@@ -4250,6 +4287,7 @@ function parseSheetState(archive, path, options) {
4250
4287
  }
4251
4288
  });
4252
4289
  return {
4290
+ autoFilterRanges,
4253
4291
  cachedFormulaValues,
4254
4292
  columnWidthCharacterWidthPx,
4255
4293
  colWidthOverridesPx,
@@ -4509,12 +4547,13 @@ function parseWorkbookStructureAssetsFromArchive(archive, options) {
4509
4547
  const workbookSheets = parseWorkbookSheets(archive);
4510
4548
  const theme = parseWorkbookTheme(archive);
4511
4549
  const themePalette = buildThemePalette(theme);
4512
- const { defaultFont, namedCellStyleByName, styleById, tableStyleByName } = parseWorkbookStyles(archive);
4550
+ const { defaultFont, differentialStyles, namedCellStyleByName, styleById, tableStyleByName } = parseWorkbookStyles(archive);
4513
4551
  return {
4514
4552
  contentTypes,
4515
4553
  namedCellStyleByName,
4516
4554
  sheetStatesByWorkbookSheetIndex: workbookSheets.map((sheet) => parseSheetState(archive, sheet.path, {
4517
4555
  ...options,
4556
+ differentialStyles,
4518
4557
  defaultFont,
4519
4558
  themePalette
4520
4559
  })),
@@ -5011,6 +5050,7 @@ function buildSheetList(nextWorkbook, structureAssets, sheetLayoutStates, showHi
5011
5050
  const usedRange = worksheet.usedRange();
5012
5051
  if (!usedRange) {
5013
5052
  sheetsByWorkbookSheetIndex.push({
5053
+ autoFilterRanges: sheetState?.autoFilterRanges ?? [],
5014
5054
  cachedFormulaValues: sheetState?.cachedFormulaValues ?? {},
5015
5055
  columnWidthCharacterWidthPx: sheetState?.columnWidthCharacterWidthPx,
5016
5056
  colCount: 0,
@@ -5071,6 +5111,7 @@ function buildSheetList(nextWorkbook, structureAssets, sheetLayoutStates, showHi
5071
5111
  }
5072
5112
  }
5073
5113
  sheetsByWorkbookSheetIndex.push({
5114
+ autoFilterRanges: sheetState?.autoFilterRanges ?? [],
5074
5115
  cachedFormulaValues: sheetState?.cachedFormulaValues ?? {},
5075
5116
  columnWidthCharacterWidthPx: sheetState?.columnWidthCharacterWidthPx,
5076
5117
  colCount: visibleCols.length,
@@ -5112,9 +5153,9 @@ function buildSheetList(nextWorkbook, structureAssets, sheetLayoutStates, showHi
5112
5153
  }
5113
5154
  return sheetsByWorkbookSheetIndex;
5114
5155
  }
5115
- function mapWorksheetTables(worksheet) {
5156
+ function mapWorksheetTables(worksheet, autoFilterRanges = []) {
5116
5157
  const rawTables = worksheet?.tables ?? [];
5117
- return rawTables.flatMap((table, index) => {
5158
+ const mappedTables = rawTables.flatMap((table, index) => {
5118
5159
  const rawColumns = Array.isArray(table.columns) ? table.columns : [];
5119
5160
  const rawName = typeof table.name === "string" ? table.name : `Table${index + 1}`;
5120
5161
  const rawDisplayName = typeof table.displayName === "string" ? table.displayName : typeof table.name === "string" ? table.name : `Table ${index + 1}`;
@@ -5142,6 +5183,34 @@ function mapWorksheetTables(worksheet) {
5142
5183
  totalsRowShown: resolveWorkbookTableBoolean(table.totalsRowShown)
5143
5184
  }];
5144
5185
  });
5186
+ const existingReferences = new Set(mappedTables.map((table) => table.reference));
5187
+ const mappedAutoFilterTables = autoFilterRanges.flatMap((range, index) => {
5188
+ const reference = `${cellAddressToA1(range.start)}:${cellAddressToA1(range.end)}`;
5189
+ if (existingReferences.has(reference)) {
5190
+ return [];
5191
+ }
5192
+ const columnCount = Math.max(0, range.end.col - range.start.col + 1);
5193
+ const columns = Array.from({ length: columnCount }, (_, columnIndex) => {
5194
+ const headerValue = worksheet ? decodeHtmlEntities(worksheet.getFormattedValueAt(range.start.row, range.start.col + columnIndex) ?? "") : "";
5195
+ return {
5196
+ id: columnIndex + 1,
5197
+ index: columnIndex,
5198
+ name: headerValue.trim().length > 0 ? headerValue : `Column ${columnIndex + 1}`
5199
+ };
5200
+ });
5201
+ return [{
5202
+ columns,
5203
+ displayName: `AutoFilter ${index + 1}`,
5204
+ end: range.end,
5205
+ headerRowCount: 1,
5206
+ name: `__autofilter_${index + 1}_${reference}`,
5207
+ reference,
5208
+ start: range.start,
5209
+ totalsRowCount: 0,
5210
+ totalsRowShown: false
5211
+ }];
5212
+ });
5213
+ return [...mappedTables, ...mappedAutoFilterTables];
5145
5214
  }
5146
5215
  function resolveWorkbookTableCount(value, fallback) {
5147
5216
  if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
@@ -5239,7 +5308,10 @@ async function loadWorkbook(buffer, skipXmlParsing = false, showHiddenSheets = f
5239
5308
  sheets = buildSheetList(nextWorkbook, structureAssets, sheetLayoutStates, showHiddenSheets);
5240
5309
  tablesByWorkbookSheetIndex = Array.from(
5241
5310
  { length: nextWorkbook.sheetCount },
5242
- (_, workbookSheetIndex) => mapWorksheetTables(nextWorkbook.getSheet(workbookSheetIndex))
5311
+ (_, workbookSheetIndex) => mapWorksheetTables(
5312
+ nextWorkbook.getSheet(workbookSheetIndex),
5313
+ structureAssets?.sheetStatesByWorkbookSheetIndex[workbookSheetIndex]?.autoFilterRanges ?? []
5314
+ )
5243
5315
  );
5244
5316
  const visibleSheetIndexByWorkbookSheetIndex = new Map(sheets.map((sheet, index) => [sheet.workbookSheetIndex, index]));
5245
5317
  const hasCharts = Array.from({ length: nextWorkbook.sheetCount }, (_, workbookSheetIndex) => {