@odoo/o-spreadsheet 19.1.2 → 19.1.3

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 19.1.2
6
- * @date 2026-01-07T16:21:36.757Z
7
- * @hash febc3e9
5
+ * @version 19.1.3
6
+ * @date 2026-01-14T10:02:32.431Z
7
+ * @hash 52a3e52
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, useExternalListener, onWillUpdateProps, onWillStart, onWillPatch, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -178,6 +178,7 @@ const DEFAULT_STYLE = {
178
178
  textColor: "",
179
179
  rotation: 0,
180
180
  };
181
+ const ROTATION_EPSILON = 0.001;
181
182
  const DEFAULT_VERTICAL_ALIGN = DEFAULT_STYLE.verticalAlign;
182
183
  const DEFAULT_WRAPPING_MODE = DEFAULT_STYLE.wrapping;
183
184
  // Fonts
@@ -15491,9 +15492,10 @@ function assertDomainLength(domain) {
15491
15492
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
15492
15493
  }
15493
15494
  }
15494
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
15495
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
15495
15496
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
15496
15497
  const dependencies = [];
15498
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
15497
15499
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
15498
15500
  const { sheetId, zone } = coreDefinition.dataSet;
15499
15501
  const xc = zoneToXc(zone);
@@ -15510,8 +15512,7 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
15510
15512
  }
15511
15513
  for (const measure of forMeasures) {
15512
15514
  if (measure.computedBy) {
15513
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
15514
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
15515
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
15515
15516
  }
15516
15517
  }
15517
15518
  const originPosition = evalContext.__originCellPosition;
@@ -16008,7 +16009,7 @@ const PIVOT_VALUE = {
16008
16009
  assertDomainLength(domainArgs);
16009
16010
  const pivot = this.getters.getPivot(pivotId);
16010
16011
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
16011
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
16012
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
16012
16013
  pivot.init({ reload: pivot.needsReevaluation });
16013
16014
  const error = pivot.assertIsValid({ throwOnError: false });
16014
16015
  if (error) {
@@ -16041,8 +16042,7 @@ const PIVOT_HEADER = {
16041
16042
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
16042
16043
  assertDomainLength(domainArgs);
16043
16044
  const pivot = this.getters.getPivot(_pivotId);
16044
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
16045
- addPivotDependencies(this, coreDefinition, []);
16045
+ addPivotDependencies(this, _pivotId, []);
16046
16046
  pivot.init({ reload: pivot.needsReevaluation });
16047
16047
  const error = pivot.assertIsValid({ throwOnError: false });
16048
16048
  if (error) {
@@ -16094,7 +16094,7 @@ const PIVOT = {
16094
16094
  if (pivotStyle.numberOfColumns < 0) {
16095
16095
  return new EvaluationError(_t("The number of columns must be positive."));
16096
16096
  }
16097
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
16097
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
16098
16098
  pivot.init({ reload: pivot.needsReevaluation });
16099
16099
  const error = pivot.assertIsValid({ throwOnError: false });
16100
16100
  if (error) {
@@ -20553,7 +20553,7 @@ function computeRotationPosition(rect, style) {
20553
20553
  let { x, y } = rect; // top-left when align=left and top-right when align=right, top-center when align=center
20554
20554
  const cos = Math.cos(-style.rotation);
20555
20555
  const sin = Math.sin(-style.rotation);
20556
- const width = rect.textWidth - MIN_CELL_TEXT_MARGIN;
20556
+ const width = rect.textWidth - 2 * MIN_CELL_TEXT_MARGIN;
20557
20557
  const height = rect.textHeight;
20558
20558
  const center = style.align === "center";
20559
20559
  const rotateTowardCellCenter = (style.align === "left") === sin < 0;
@@ -20587,6 +20587,13 @@ function computeRotationPosition(rect, style) {
20587
20587
  else {
20588
20588
  if (center) {
20589
20589
  x -= sh / 2;
20590
+ y -= height / 2;
20591
+ if (rotateTowardCellCenter) {
20592
+ y += sh;
20593
+ }
20594
+ else {
20595
+ y -= sh;
20596
+ }
20590
20597
  }
20591
20598
  else if (rotateTowardCellCenter) {
20592
20599
  x -= sh;
@@ -34399,6 +34406,328 @@ function hexaToInt(hex) {
34399
34406
  */
34400
34407
  const DEFAULT_SYSTEM_COLOR = "FF000000";
34401
34408
 
34409
+ // -------------------------------------
34410
+ // CF HELPERS
34411
+ // -------------------------------------
34412
+ /**
34413
+ * Convert the conditional formatting o-spreadsheet operator to
34414
+ * the corresponding excel operator.
34415
+ * */
34416
+ function convertOperator(operator) {
34417
+ switch (operator) {
34418
+ case "isNotEmpty":
34419
+ return "notContainsBlanks";
34420
+ case "isEmpty":
34421
+ return "containsBlanks";
34422
+ case "notContainsText":
34423
+ return "notContainsBlanks";
34424
+ case "containsText":
34425
+ return "containsText";
34426
+ case "beginsWithText":
34427
+ return "beginsWith";
34428
+ case "endsWithText":
34429
+ return "endsWith";
34430
+ case "isGreaterThan":
34431
+ return "greaterThan";
34432
+ case "isGreaterOrEqualTo":
34433
+ return "greaterThanOrEqual";
34434
+ case "isLessThan":
34435
+ return "lessThan";
34436
+ case "isLessOrEqualTo":
34437
+ return "lessThanOrEqual";
34438
+ case "isBetween":
34439
+ return "between";
34440
+ case "isNotBetween":
34441
+ return "notBetween";
34442
+ case "isEqual":
34443
+ return "equal";
34444
+ case "isNotEqual":
34445
+ return "notEqual";
34446
+ case "customFormula":
34447
+ return "";
34448
+ case "dateIs":
34449
+ return "";
34450
+ case "dateIsBefore":
34451
+ return "lessThan";
34452
+ case "dateIsAfter":
34453
+ return "greaterThan";
34454
+ case "dateIsOnOrAfter":
34455
+ return "greaterThanOrEqual";
34456
+ case "dateIsOnOrBefore":
34457
+ return "lessThanOrEqual";
34458
+ }
34459
+ }
34460
+ // -------------------------------------
34461
+ // WORKSHEET HELPERS
34462
+ // -------------------------------------
34463
+ function getCellType(value) {
34464
+ switch (typeof value) {
34465
+ case "boolean":
34466
+ return "b";
34467
+ case "string":
34468
+ return "str";
34469
+ case "number":
34470
+ return "n";
34471
+ default:
34472
+ return undefined;
34473
+ }
34474
+ }
34475
+ function convertHeightToExcel(height) {
34476
+ return Math.round(HEIGHT_FACTOR * height * 100) / 100;
34477
+ }
34478
+ function convertWidthToExcel(width) {
34479
+ return Math.round(WIDTH_FACTOR * width * 100) / 100;
34480
+ }
34481
+ function convertHeightFromExcel(height) {
34482
+ if (!height)
34483
+ return height;
34484
+ return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
34485
+ }
34486
+ function convertWidthFromExcel(width) {
34487
+ if (!width)
34488
+ return width;
34489
+ return Math.round((width / WIDTH_FACTOR) * 100) / 100;
34490
+ }
34491
+ function extractStyle(data, content, styleId, formatId, borderId) {
34492
+ const style = styleId ? data.styles[styleId] : {};
34493
+ const format = formatId ? data.formats[formatId] : undefined;
34494
+ const styles = {
34495
+ font: {
34496
+ size: style?.fontSize || DEFAULT_FONT_SIZE,
34497
+ color: { rgb: style?.textColor ? style.textColor : "000000" },
34498
+ family: 2,
34499
+ name: "Arial",
34500
+ },
34501
+ fill: style?.fillColor
34502
+ ? {
34503
+ fgColor: { rgb: style.fillColor },
34504
+ }
34505
+ : { reservedAttribute: "none" },
34506
+ numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
34507
+ border: borderId || 0,
34508
+ alignment: {
34509
+ horizontal: style.align,
34510
+ vertical: style.verticalAlign
34511
+ ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
34512
+ : undefined,
34513
+ wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
34514
+ textRotation: style.rotation ? rotationToXLSX(style.rotation) : undefined,
34515
+ },
34516
+ };
34517
+ styles.font["strike"] = !!style?.strikethrough || undefined;
34518
+ styles.font["underline"] = !!style?.underline || undefined;
34519
+ styles.font["bold"] = !!style?.bold || undefined;
34520
+ styles.font["italic"] = !!style?.italic || undefined;
34521
+ return styles;
34522
+ }
34523
+ function rotationToXLSX(rad) {
34524
+ let deg = Math.round((-rad / Math.PI) * 180) % 180;
34525
+ if (deg > 90) {
34526
+ deg -= 180;
34527
+ }
34528
+ else if (deg < -90) {
34529
+ deg += 180;
34530
+ }
34531
+ if (deg >= 0) {
34532
+ return deg;
34533
+ }
34534
+ else {
34535
+ return 90 - deg;
34536
+ }
34537
+ }
34538
+ function rotationFromXLSX(deg) {
34539
+ if (deg <= 90) {
34540
+ return -(deg / 180) * Math.PI;
34541
+ }
34542
+ else {
34543
+ return (-(90 - deg) / 180) * Math.PI;
34544
+ }
34545
+ }
34546
+ function normalizeStyle(construct, styles) {
34547
+ // Normalize this
34548
+ const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
34549
+ const style = {
34550
+ fontId: pushElement(styles.font, construct.fonts),
34551
+ fillId: pushElement(styles.fill, construct.fills),
34552
+ borderId: styles.border,
34553
+ numFmtId,
34554
+ alignment: {
34555
+ vertical: styles.alignment.vertical,
34556
+ horizontal: styles.alignment.horizontal,
34557
+ wrapText: styles.alignment.wrapText,
34558
+ textRotation: styles.alignment.textRotation,
34559
+ },
34560
+ };
34561
+ return pushElement(style, construct.styles);
34562
+ }
34563
+ function convertFormat(format, numFmtStructure) {
34564
+ if (!format) {
34565
+ return 0;
34566
+ }
34567
+ let formatId = XLSX_FORMAT_MAP[format.format];
34568
+ if (!formatId) {
34569
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
34570
+ }
34571
+ return formatId;
34572
+ }
34573
+ /**
34574
+ * Add a relation to the given file and return its id.
34575
+ */
34576
+ function addRelsToFile(relsFiles, path, rel) {
34577
+ const relsFile = relsFiles.find((file) => file.path === path);
34578
+ // the id is a one-based int casted as string
34579
+ let id;
34580
+ if (!relsFile) {
34581
+ id = "rId1";
34582
+ relsFiles.push({ path, rels: [{ ...rel, id }] });
34583
+ }
34584
+ else {
34585
+ id = `rId${(relsFile.rels.length + 1).toString()}`;
34586
+ relsFile.rels.push({
34587
+ ...rel,
34588
+ id,
34589
+ });
34590
+ }
34591
+ return id;
34592
+ }
34593
+ const globalReverseLookup = new WeakMap();
34594
+ function pushElement(property, propertyList) {
34595
+ let reverseLookup = globalReverseLookup.get(propertyList);
34596
+ if (!reverseLookup) {
34597
+ reverseLookup = new Map();
34598
+ for (let i = 0; i < propertyList.length; i++) {
34599
+ const canonical = getCanonicalRepresentation(propertyList[i]);
34600
+ reverseLookup.set(canonical, i);
34601
+ }
34602
+ globalReverseLookup.set(propertyList, reverseLookup);
34603
+ }
34604
+ const canonical = getCanonicalRepresentation(property);
34605
+ if (reverseLookup.has(canonical)) {
34606
+ return reverseLookup.get(canonical);
34607
+ }
34608
+ const maxId = propertyList.length;
34609
+ propertyList.push(property);
34610
+ reverseLookup.set(canonical, maxId);
34611
+ return maxId;
34612
+ }
34613
+ /**
34614
+ * Convert a chart o-spreadsheet id to a xlsx id which
34615
+ * are unsigned integers (starting from 1).
34616
+ */
34617
+ function convertChartId(chartId, construct) {
34618
+ const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
34619
+ if (xlsxId === -1) {
34620
+ construct.chartIds.push(chartId);
34621
+ return construct.chartIds.length;
34622
+ }
34623
+ return xlsxId + 1;
34624
+ }
34625
+ const imageIds = [];
34626
+ /**
34627
+ * Convert a image o-spreadsheet id to a xlsx id which
34628
+ * are unsigned integers (starting from 1).
34629
+ */
34630
+ function convertImageId(imageId) {
34631
+ const xlsxId = imageIds.findIndex((id) => id === imageId);
34632
+ if (xlsxId === -1) {
34633
+ imageIds.push(imageId);
34634
+ return imageIds.length;
34635
+ }
34636
+ return xlsxId + 1;
34637
+ }
34638
+ /**
34639
+ * Convert a value expressed in dot to EMU.
34640
+ * EMU = English Metrical Unit
34641
+ * There are 914400 EMU per inch.
34642
+ *
34643
+ * /!\ A value expressed in EMU cannot be fractional.
34644
+ * See https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vml-units#other-units-of-measurement
34645
+ */
34646
+ function convertDotValueToEMU(value) {
34647
+ const DPI = 96;
34648
+ return Math.round((value * 914400) / DPI);
34649
+ }
34650
+ function getRangeSize(reference, defaultSheetIndex, data) {
34651
+ let xc = reference;
34652
+ let sheetName = undefined;
34653
+ ({ xc, sheetName } = splitReference(reference));
34654
+ let rangeSheetIndex;
34655
+ if (sheetName) {
34656
+ const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
34657
+ if (index < 0) {
34658
+ throw new Error("Unable to find a sheet with the name " + sheetName);
34659
+ }
34660
+ rangeSheetIndex = index;
34661
+ }
34662
+ else {
34663
+ rangeSheetIndex = Number(defaultSheetIndex);
34664
+ }
34665
+ const zone = toUnboundedZone(xc);
34666
+ if (zone.right === undefined) {
34667
+ zone.right = data.sheets[rangeSheetIndex].colNumber;
34668
+ }
34669
+ if (zone.bottom === undefined) {
34670
+ zone.bottom = data.sheets[rangeSheetIndex].rowNumber;
34671
+ }
34672
+ return (zone.right - zone.left + 1) * (zone.bottom - zone.top + 1);
34673
+ }
34674
+ function convertEMUToDotValue(value) {
34675
+ const DPI = 96;
34676
+ return Math.round((value * DPI) / 914400);
34677
+ }
34678
+ /**
34679
+ * Get the position of the start of a column in Excel (in px).
34680
+ */
34681
+ function getColPosition(colIndex, sheetData) {
34682
+ let position = 0;
34683
+ for (let i = 0; i < colIndex; i++) {
34684
+ const colAtIndex = sheetData.cols.find((col) => i >= col.min && i <= col.max);
34685
+ if (colAtIndex?.width) {
34686
+ position += colAtIndex.width;
34687
+ }
34688
+ else if (sheetData.sheetFormat?.defaultColWidth) {
34689
+ position += sheetData.sheetFormat.defaultColWidth;
34690
+ }
34691
+ else {
34692
+ position += EXCEL_DEFAULT_COL_WIDTH;
34693
+ }
34694
+ }
34695
+ return position / WIDTH_FACTOR;
34696
+ }
34697
+ /**
34698
+ * Get the position of the start of a row in Excel (in px).
34699
+ */
34700
+ function getRowPosition(rowIndex, sheetData) {
34701
+ let position = 0;
34702
+ for (let i = 0; i < rowIndex; i++) {
34703
+ const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
34704
+ if (rowAtIndex?.height) {
34705
+ position += rowAtIndex.height;
34706
+ }
34707
+ else if (sheetData.sheetFormat?.defaultRowHeight) {
34708
+ position += sheetData.sheetFormat.defaultRowHeight;
34709
+ }
34710
+ else {
34711
+ position += EXCEL_DEFAULT_ROW_HEIGHT;
34712
+ }
34713
+ }
34714
+ return position / HEIGHT_FACTOR;
34715
+ }
34716
+ /**
34717
+ * Convert the o-spreadsheet data validation decimal
34718
+ * criterion type to the corresponding excel operator.
34719
+ */
34720
+ function convertDecimalCriterionTypeToExcelOperator(operator) {
34721
+ return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
34722
+ }
34723
+ /**
34724
+ * Convert the o-spreadsheet data validation date
34725
+ * criterion type to the corresponding excel operator.
34726
+ */
34727
+ function convertDateCriterionTypeToExcelOperator(operator) {
34728
+ return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
34729
+ }
34730
+
34402
34731
  const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
34403
34732
  /**
34404
34733
  * Convert excel format to o_spreadsheet format
@@ -34498,6 +34827,9 @@ function convertStyle(styleStruct, warningManager) {
34498
34827
  align: styleStruct.alignment?.horizontal
34499
34828
  ? H_ALIGNMENT_CONVERSION_MAP[styleStruct.alignment.horizontal]
34500
34829
  : undefined,
34830
+ rotation: styleStruct.alignment?.textRotation
34831
+ ? rotationFromXLSX(styleStruct.alignment.textRotation)
34832
+ : undefined,
34501
34833
  // In xlsx fills, bgColor is the color of the fill, and fgColor is the color of the pattern above the background, except in solid fills
34502
34834
  fillColor: styleStruct.fillStyle?.patternType === "solid"
34503
34835
  ? convertColor(styleStruct.fillStyle?.fgColor)
@@ -34797,303 +35129,6 @@ function addCfConversionWarnings(cf, dxfs, warningManager) {
34797
35129
  }
34798
35130
  }
34799
35131
 
34800
- // -------------------------------------
34801
- // CF HELPERS
34802
- // -------------------------------------
34803
- /**
34804
- * Convert the conditional formatting o-spreadsheet operator to
34805
- * the corresponding excel operator.
34806
- * */
34807
- function convertOperator(operator) {
34808
- switch (operator) {
34809
- case "isNotEmpty":
34810
- return "notContainsBlanks";
34811
- case "isEmpty":
34812
- return "containsBlanks";
34813
- case "notContainsText":
34814
- return "notContainsBlanks";
34815
- case "containsText":
34816
- return "containsText";
34817
- case "beginsWithText":
34818
- return "beginsWith";
34819
- case "endsWithText":
34820
- return "endsWith";
34821
- case "isGreaterThan":
34822
- return "greaterThan";
34823
- case "isGreaterOrEqualTo":
34824
- return "greaterThanOrEqual";
34825
- case "isLessThan":
34826
- return "lessThan";
34827
- case "isLessOrEqualTo":
34828
- return "lessThanOrEqual";
34829
- case "isBetween":
34830
- return "between";
34831
- case "isNotBetween":
34832
- return "notBetween";
34833
- case "isEqual":
34834
- return "equal";
34835
- case "isNotEqual":
34836
- return "notEqual";
34837
- case "customFormula":
34838
- return "";
34839
- case "dateIs":
34840
- return "";
34841
- case "dateIsBefore":
34842
- return "lessThan";
34843
- case "dateIsAfter":
34844
- return "greaterThan";
34845
- case "dateIsOnOrAfter":
34846
- return "greaterThanOrEqual";
34847
- case "dateIsOnOrBefore":
34848
- return "lessThanOrEqual";
34849
- }
34850
- }
34851
- // -------------------------------------
34852
- // WORKSHEET HELPERS
34853
- // -------------------------------------
34854
- function getCellType(value) {
34855
- switch (typeof value) {
34856
- case "boolean":
34857
- return "b";
34858
- case "string":
34859
- return "str";
34860
- case "number":
34861
- return "n";
34862
- default:
34863
- return undefined;
34864
- }
34865
- }
34866
- function convertHeightToExcel(height) {
34867
- return Math.round(HEIGHT_FACTOR * height * 100) / 100;
34868
- }
34869
- function convertWidthToExcel(width) {
34870
- return Math.round(WIDTH_FACTOR * width * 100) / 100;
34871
- }
34872
- function convertHeightFromExcel(height) {
34873
- if (!height)
34874
- return height;
34875
- return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
34876
- }
34877
- function convertWidthFromExcel(width) {
34878
- if (!width)
34879
- return width;
34880
- return Math.round((width / WIDTH_FACTOR) * 100) / 100;
34881
- }
34882
- function extractStyle(data, content, styleId, formatId, borderId) {
34883
- const style = styleId ? data.styles[styleId] : {};
34884
- const format = formatId ? data.formats[formatId] : undefined;
34885
- const styles = {
34886
- font: {
34887
- size: style?.fontSize || DEFAULT_FONT_SIZE,
34888
- color: { rgb: style?.textColor ? style.textColor : "000000" },
34889
- family: 2,
34890
- name: "Arial",
34891
- },
34892
- fill: style?.fillColor
34893
- ? {
34894
- fgColor: { rgb: style.fillColor },
34895
- }
34896
- : { reservedAttribute: "none" },
34897
- numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
34898
- border: borderId || 0,
34899
- alignment: {
34900
- horizontal: style.align,
34901
- vertical: style.verticalAlign
34902
- ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
34903
- : undefined,
34904
- wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
34905
- },
34906
- };
34907
- styles.font["strike"] = !!style?.strikethrough || undefined;
34908
- styles.font["underline"] = !!style?.underline || undefined;
34909
- styles.font["bold"] = !!style?.bold || undefined;
34910
- styles.font["italic"] = !!style?.italic || undefined;
34911
- return styles;
34912
- }
34913
- function normalizeStyle(construct, styles) {
34914
- // Normalize this
34915
- const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
34916
- const style = {
34917
- fontId: pushElement(styles.font, construct.fonts),
34918
- fillId: pushElement(styles.fill, construct.fills),
34919
- borderId: styles.border,
34920
- numFmtId,
34921
- alignment: {
34922
- vertical: styles.alignment.vertical,
34923
- horizontal: styles.alignment.horizontal,
34924
- wrapText: styles.alignment.wrapText,
34925
- },
34926
- };
34927
- return pushElement(style, construct.styles);
34928
- }
34929
- function convertFormat(format, numFmtStructure) {
34930
- if (!format) {
34931
- return 0;
34932
- }
34933
- let formatId = XLSX_FORMAT_MAP[format.format];
34934
- if (!formatId) {
34935
- formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
34936
- }
34937
- return formatId;
34938
- }
34939
- /**
34940
- * Add a relation to the given file and return its id.
34941
- */
34942
- function addRelsToFile(relsFiles, path, rel) {
34943
- const relsFile = relsFiles.find((file) => file.path === path);
34944
- // the id is a one-based int casted as string
34945
- let id;
34946
- if (!relsFile) {
34947
- id = "rId1";
34948
- relsFiles.push({ path, rels: [{ ...rel, id }] });
34949
- }
34950
- else {
34951
- id = `rId${(relsFile.rels.length + 1).toString()}`;
34952
- relsFile.rels.push({
34953
- ...rel,
34954
- id,
34955
- });
34956
- }
34957
- return id;
34958
- }
34959
- const globalReverseLookup = new WeakMap();
34960
- function pushElement(property, propertyList) {
34961
- let reverseLookup = globalReverseLookup.get(propertyList);
34962
- if (!reverseLookup) {
34963
- reverseLookup = new Map();
34964
- for (let i = 0; i < propertyList.length; i++) {
34965
- const canonical = getCanonicalRepresentation(propertyList[i]);
34966
- reverseLookup.set(canonical, i);
34967
- }
34968
- globalReverseLookup.set(propertyList, reverseLookup);
34969
- }
34970
- const canonical = getCanonicalRepresentation(property);
34971
- if (reverseLookup.has(canonical)) {
34972
- return reverseLookup.get(canonical);
34973
- }
34974
- const maxId = propertyList.length;
34975
- propertyList.push(property);
34976
- reverseLookup.set(canonical, maxId);
34977
- return maxId;
34978
- }
34979
- /**
34980
- * Convert a chart o-spreadsheet id to a xlsx id which
34981
- * are unsigned integers (starting from 1).
34982
- */
34983
- function convertChartId(chartId, construct) {
34984
- const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
34985
- if (xlsxId === -1) {
34986
- construct.chartIds.push(chartId);
34987
- return construct.chartIds.length;
34988
- }
34989
- return xlsxId + 1;
34990
- }
34991
- const imageIds = [];
34992
- /**
34993
- * Convert a image o-spreadsheet id to a xlsx id which
34994
- * are unsigned integers (starting from 1).
34995
- */
34996
- function convertImageId(imageId) {
34997
- const xlsxId = imageIds.findIndex((id) => id === imageId);
34998
- if (xlsxId === -1) {
34999
- imageIds.push(imageId);
35000
- return imageIds.length;
35001
- }
35002
- return xlsxId + 1;
35003
- }
35004
- /**
35005
- * Convert a value expressed in dot to EMU.
35006
- * EMU = English Metrical Unit
35007
- * There are 914400 EMU per inch.
35008
- *
35009
- * /!\ A value expressed in EMU cannot be fractional.
35010
- * See https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vml-units#other-units-of-measurement
35011
- */
35012
- function convertDotValueToEMU(value) {
35013
- const DPI = 96;
35014
- return Math.round((value * 914400) / DPI);
35015
- }
35016
- function getRangeSize(reference, defaultSheetIndex, data) {
35017
- let xc = reference;
35018
- let sheetName = undefined;
35019
- ({ xc, sheetName } = splitReference(reference));
35020
- let rangeSheetIndex;
35021
- if (sheetName) {
35022
- const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
35023
- if (index < 0) {
35024
- throw new Error("Unable to find a sheet with the name " + sheetName);
35025
- }
35026
- rangeSheetIndex = index;
35027
- }
35028
- else {
35029
- rangeSheetIndex = Number(defaultSheetIndex);
35030
- }
35031
- const zone = toUnboundedZone(xc);
35032
- if (zone.right === undefined) {
35033
- zone.right = data.sheets[rangeSheetIndex].colNumber;
35034
- }
35035
- if (zone.bottom === undefined) {
35036
- zone.bottom = data.sheets[rangeSheetIndex].rowNumber;
35037
- }
35038
- return (zone.right - zone.left + 1) * (zone.bottom - zone.top + 1);
35039
- }
35040
- function convertEMUToDotValue(value) {
35041
- const DPI = 96;
35042
- return Math.round((value * DPI) / 914400);
35043
- }
35044
- /**
35045
- * Get the position of the start of a column in Excel (in px).
35046
- */
35047
- function getColPosition(colIndex, sheetData) {
35048
- let position = 0;
35049
- for (let i = 0; i < colIndex; i++) {
35050
- const colAtIndex = sheetData.cols.find((col) => i >= col.min && i <= col.max);
35051
- if (colAtIndex?.width) {
35052
- position += colAtIndex.width;
35053
- }
35054
- else if (sheetData.sheetFormat?.defaultColWidth) {
35055
- position += sheetData.sheetFormat.defaultColWidth;
35056
- }
35057
- else {
35058
- position += EXCEL_DEFAULT_COL_WIDTH;
35059
- }
35060
- }
35061
- return position / WIDTH_FACTOR;
35062
- }
35063
- /**
35064
- * Get the position of the start of a row in Excel (in px).
35065
- */
35066
- function getRowPosition(rowIndex, sheetData) {
35067
- let position = 0;
35068
- for (let i = 0; i < rowIndex; i++) {
35069
- const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
35070
- if (rowAtIndex?.height) {
35071
- position += rowAtIndex.height;
35072
- }
35073
- else if (sheetData.sheetFormat?.defaultRowHeight) {
35074
- position += sheetData.sheetFormat.defaultRowHeight;
35075
- }
35076
- else {
35077
- position += EXCEL_DEFAULT_ROW_HEIGHT;
35078
- }
35079
- }
35080
- return position / HEIGHT_FACTOR;
35081
- }
35082
- /**
35083
- * Convert the o-spreadsheet data validation decimal
35084
- * criterion type to the corresponding excel operator.
35085
- */
35086
- function convertDecimalCriterionTypeToExcelOperator(operator) {
35087
- return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
35088
- }
35089
- /**
35090
- * Convert the o-spreadsheet data validation date
35091
- * criterion type to the corresponding excel operator.
35092
- */
35093
- function convertDateCriterionTypeToExcelOperator(operator) {
35094
- return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
35095
- }
35096
-
35097
35132
  function convertFigures(sheetData) {
35098
35133
  let id = 1;
35099
35134
  return sheetData.figures
@@ -44674,6 +44709,7 @@ class PivotCorePlugin extends CorePlugin {
44674
44709
  "getMeasureCompiledFormula",
44675
44710
  "getPivotName",
44676
44711
  "isExistingPivot",
44712
+ "getMeasureFullDependencies",
44677
44713
  ];
44678
44714
  nextFormulaId = 1;
44679
44715
  pivots = {};
@@ -44759,7 +44795,7 @@ class PivotCorePlugin extends CorePlugin {
44759
44795
  }
44760
44796
  case "UPDATE_PIVOT": {
44761
44797
  this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
44762
- this.compileCalculatedMeasures(cmd.pivot.measures);
44798
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
44763
44799
  break;
44764
44800
  }
44765
44801
  }
@@ -44777,9 +44813,14 @@ class PivotCorePlugin extends CorePlugin {
44777
44813
  this.history.update("pivots", pivotId, "definition", newDefinition);
44778
44814
  }
44779
44815
  }
44780
- for (const sheetId in this.compiledMeasureFormulas) {
44781
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
44782
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
44816
+ for (const pivotId in this.compiledMeasureFormulas) {
44817
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
44818
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
44819
+ if (!measure || !measure.computedBy) {
44820
+ continue;
44821
+ }
44822
+ const sheetId = measure.computedBy.sheetId;
44823
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
44783
44824
  const newDependencies = [];
44784
44825
  for (const range of compiledFormula.dependencies) {
44785
44826
  const change = applyChange(range);
@@ -44791,8 +44832,9 @@ class PivotCorePlugin extends CorePlugin {
44791
44832
  }
44792
44833
  }
44793
44834
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
44794
- if (newFormulaString !== formulaString) {
44795
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
44835
+ const oldFormulaString = measure.computedBy.formula;
44836
+ if (newFormulaString !== oldFormulaString) {
44837
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
44796
44838
  }
44797
44839
  }
44798
44840
  }
@@ -44830,30 +44872,59 @@ class PivotCorePlugin extends CorePlugin {
44830
44872
  isExistingPivot(pivotId) {
44831
44873
  return pivotId in this.pivots;
44832
44874
  }
44833
- getMeasureCompiledFormula(measure) {
44875
+ getMeasureCompiledFormula(pivotId, measure) {
44876
+ if (!measure.computedBy) {
44877
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
44878
+ }
44879
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
44880
+ }
44881
+ getMeasureFullDependencies(pivotId, measure) {
44834
44882
  if (!measure.computedBy) {
44835
44883
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
44836
44884
  }
44837
- const sheetId = measure.computedBy.sheetId;
44838
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
44885
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
44839
44886
  }
44840
44887
  // -------------------------------------------------------------------------
44841
44888
  // Private
44842
44889
  // -------------------------------------------------------------------------
44843
44890
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
44844
44891
  this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
44845
- this.compileCalculatedMeasures(pivot.measures);
44892
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
44846
44893
  this.history.update("formulaIds", formulaId, pivotId);
44847
44894
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
44848
44895
  }
44849
- compileCalculatedMeasures(measures) {
44896
+ compileCalculatedMeasures(pivotId, measures) {
44850
44897
  for (const measure of measures) {
44851
44898
  if (measure.computedBy) {
44852
- const sheetId = measure.computedBy.sheetId;
44853
44899
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
44854
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
44900
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
44901
+ }
44902
+ }
44903
+ for (const measure of measures) {
44904
+ if (measure.computedBy) {
44905
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
44906
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
44907
+ }
44908
+ }
44909
+ }
44910
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
44911
+ const rangeDependencies = [];
44912
+ const definition = this.getPivotCoreDefinition(pivotId);
44913
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
44914
+ exploredMeasures.add(measure.id);
44915
+ for (const token of formula.tokens) {
44916
+ if (token.type !== "SYMBOL") {
44917
+ continue;
44918
+ }
44919
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
44920
+ measure.id !== measureCandidate.id);
44921
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
44922
+ continue;
44855
44923
  }
44924
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
44856
44925
  }
44926
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
44927
+ return rangeDependencies;
44857
44928
  }
44858
44929
  insertPivot(position, formulaId, table) {
44859
44930
  this.resizeSheet(position.sheetId, position, table);
@@ -44913,21 +44984,17 @@ class PivotCorePlugin extends CorePlugin {
44913
44984
  dependencies: rangeDependencies,
44914
44985
  };
44915
44986
  }
44916
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
44917
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
44918
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
44919
- for (const pivotId in this.pivots) {
44920
- const pivot = this.pivots[pivotId];
44921
- if (!pivot) {
44922
- continue;
44923
- }
44924
- for (const measure of pivot.definition.measures) {
44925
- if (measure.computedBy?.formula === formulaString) {
44926
- const measureIndex = pivot.definition.measures.indexOf(measure);
44927
- this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
44928
- }
44929
- }
44987
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
44988
+ const pivot = this.pivots[pivotId];
44989
+ if (!pivot) {
44990
+ return;
44930
44991
  }
44992
+ const measureIndex = pivot.definition.measures.indexOf(measure);
44993
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
44994
+ formula: newFormulaString,
44995
+ sheetId: measure.computedBy.sheetId,
44996
+ });
44997
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
44931
44998
  }
44932
44999
  checkSortedColumnInMeasures(definition) {
44933
45000
  const measures = definition.measures.map((measure) => measure.id);
@@ -45988,7 +46055,7 @@ class StylePlugin extends CorePlugin {
45988
46055
  case "UPDATE_CELL":
45989
46056
  if (cmd.style !== undefined) {
45990
46057
  if (cmd.style !== null) {
45991
- this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style);
46058
+ this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style, { force: true });
45992
46059
  }
45993
46060
  else {
45994
46061
  this.clearStyle(cmd.sheetId, [positionToZone(cmd)]);
@@ -46056,16 +46123,22 @@ class StylePlugin extends CorePlugin {
46056
46123
  }
46057
46124
  }
46058
46125
  styleIsDefault(style) {
46059
- return deepEquals(this.removeDefaultStyleValues(style), {});
46126
+ for (const key in style) {
46127
+ if (DEFAULT_STYLE_NO_ALIGN[key] !== style[key]) {
46128
+ return false;
46129
+ }
46130
+ }
46131
+ return true;
46060
46132
  }
46061
46133
  removeDefaultStyleValues(style) {
46062
46134
  const cleanedStyle = { ...style };
46063
- for (const property in DEFAULT_STYLE_NO_ALIGN) {
46064
- if (cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
46135
+ for (const property in style) {
46136
+ if (cleanedStyle[property] === undefined ||
46137
+ cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
46065
46138
  delete cleanedStyle[property];
46066
46139
  }
46067
46140
  }
46068
- return cleanedStyle;
46141
+ return Object.keys(cleanedStyle).length > 0 ? cleanedStyle : undefined;
46069
46142
  }
46070
46143
  onMerge(sheetId, zone) {
46071
46144
  this.setStyle(sheetId, zone, this.getCellStyle({ sheetId, col: zone.left, row: zone.top }), {
@@ -46101,13 +46174,13 @@ class StylePlugin extends CorePlugin {
46101
46174
  }
46102
46175
  editingZone = recomputeZones(editingZone, [inter]);
46103
46176
  }
46177
+ style = this.removeDefaultStyleValues(style);
46104
46178
  if (style) {
46105
- const newStyle = this.removeDefaultStyleValues(style);
46106
46179
  styles.push(...editingZone.map((zone) => {
46107
- return { zone, style: newStyle };
46180
+ return { zone, style };
46108
46181
  }));
46109
46182
  }
46110
- this.history.update("styles", sheetId, styles.filter((zoneStyle) => !this.styleIsDefault(zoneStyle.style)));
46183
+ this.history.update("styles", sheetId, styles);
46111
46184
  }
46112
46185
  clearStyle(sheetId, zones) {
46113
46186
  this.setStyles(sheetId, zones, undefined, { force: true });
@@ -52036,14 +52109,16 @@ const PERCENT_FORMAT = "0.00%";
52036
52109
  function withPivotPresentationLayer (PivotClass) {
52037
52110
  class PivotPresentationLayer extends PivotClass {
52038
52111
  getters;
52112
+ pivotId;
52039
52113
  cache = {};
52040
52114
  rankAsc = {};
52041
52115
  rankDesc = {};
52042
52116
  runningTotal = {};
52043
52117
  runningTotalInPercent = {};
52044
- constructor(custom, params) {
52118
+ constructor(pivotId, custom, params) {
52045
52119
  super(custom, params);
52046
52120
  this.getters = params.getters;
52121
+ this.pivotId = pivotId;
52047
52122
  }
52048
52123
  markAsDirtyForEvaluation() {
52049
52124
  this.cache = {};
@@ -52093,7 +52168,7 @@ function withPivotPresentationLayer (PivotClass) {
52093
52168
  return handleError(error, measure.aggregator.toUpperCase());
52094
52169
  }
52095
52170
  }
52096
- const formula = this.getters.getMeasureCompiledFormula(measure);
52171
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
52097
52172
  const getSymbolValue = (symbolName) => {
52098
52173
  const { columns, rows } = this.definition;
52099
52174
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -52840,7 +52915,7 @@ class PivotUIPlugin extends CoreViewPlugin {
52840
52915
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
52841
52916
  if (!(pivotId in this.pivots)) {
52842
52917
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
52843
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
52918
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
52844
52919
  }
52845
52920
  else if (recreate) {
52846
52921
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -61938,6 +62013,9 @@ function addStyles(styles) {
61938
62013
  if (style.alignment && style.alignment.wrapText) {
61939
62014
  alignAttrs.push(["wrapText", "1"]);
61940
62015
  }
62016
+ if (style.alignment && style.alignment.textRotation) {
62017
+ alignAttrs.push(["textRotation", style.alignment.textRotation]);
62018
+ }
61941
62019
  if (alignAttrs.length > 0) {
61942
62020
  attributes.push(["applyAlignment", "1"]); // for Libre Office
61943
62021
  styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}><alignment ${formatAttributes(alignAttrs)} /></xf> `);
@@ -72238,7 +72316,7 @@ class AbstractComposerStore extends SpreadsheetStore {
72238
72316
  }
72239
72317
  captureSelection(zone, col, row) {
72240
72318
  this.model.selection.capture(this, {
72241
- cell: { col: col ?? zone.left, row: row ?? zone.right },
72319
+ cell: { col: col ?? zone.left, row: row ?? zone.top },
72242
72320
  zone,
72243
72321
  }, {
72244
72322
  handleEvent: this.handleEvent.bind(this),
@@ -77961,35 +78039,46 @@ const formatRotation = {
77961
78039
  name: _t("Rotation"),
77962
78040
  icon: (env) => getRotationIcon(env),
77963
78041
  };
78042
+ function setRotation(env, rotation) {
78043
+ rotation = Math.trunc(rotation / ROTATION_EPSILON) * ROTATION_EPSILON;
78044
+ setStyle(env, { rotation });
78045
+ }
78046
+ function currentRotationEqual(env, rotation) {
78047
+ const current = env.model.getters.getCurrentStyle().rotation;
78048
+ if (current === undefined) {
78049
+ return rotation === 0;
78050
+ }
78051
+ return Math.abs(current - rotation) < ROTATION_EPSILON;
78052
+ }
77964
78053
  const formatNoRotation = {
77965
78054
  name: _t("No rotation"),
77966
78055
  execute: (env) => setStyle(env, { rotation: 0 }),
77967
78056
  icon: "o-spreadsheet-Icon.ROTATION-0",
77968
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === 0,
78057
+ isActive: (env) => currentRotationEqual(env, 0),
77969
78058
  };
77970
78059
  const formatRotation45 = {
77971
78060
  name: _t("45° rotation"),
77972
- execute: (env) => setStyle(env, { rotation: Math.PI / 4 }),
78061
+ execute: (env) => setRotation(env, Math.PI / 4),
77973
78062
  icon: "o-spreadsheet-Icon.ROTATION-45",
77974
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === Math.PI / 4,
78063
+ isActive: (env) => currentRotationEqual(env, Math.PI / 4),
77975
78064
  };
77976
78065
  const formatRotation90 = {
77977
78066
  name: _t("90° rotation"),
77978
- execute: (env) => setStyle(env, { rotation: Math.PI / 2 }),
78067
+ execute: (env) => setRotation(env, Math.PI / 2),
77979
78068
  icon: "o-spreadsheet-Icon.ROTATION-90",
77980
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === Math.PI / 2,
78069
+ isActive: (env) => currentRotationEqual(env, Math.PI / 2),
77981
78070
  };
77982
78071
  const formatRotation270 = {
77983
78072
  name: _t("-90° rotation"),
77984
- execute: (env) => setStyle(env, { rotation: -Math.PI / 2 }),
78073
+ execute: (env) => setRotation(env, -Math.PI / 2),
77985
78074
  icon: "o-spreadsheet-Icon.ROTATION-270",
77986
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === -Math.PI / 2,
78075
+ isActive: (env) => currentRotationEqual(env, -Math.PI / 2),
77987
78076
  };
77988
78077
  const formatRotation315 = {
77989
78078
  name: _t("-45° rotation"),
77990
- execute: (env) => setStyle(env, { rotation: -Math.PI / 4 }),
78079
+ execute: (env) => setRotation(env, -Math.PI / 4),
77991
78080
  icon: "o-spreadsheet-Icon.ROTATION-315",
77992
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === -Math.PI / 4,
78081
+ isActive: (env) => currentRotationEqual(env, -Math.PI / 4),
77993
78082
  };
77994
78083
  const formatStrikethrough = {
77995
78084
  name: _t("Strikethrough"),
@@ -78155,10 +78244,6 @@ function getWrappingMode(env) {
78155
78244
  }
78156
78245
  return DEFAULT_WRAPPING_MODE;
78157
78246
  }
78158
- function getRotation(env) {
78159
- const style = env.model.getters.getCurrentStyle();
78160
- return style.rotation ?? 0;
78161
- }
78162
78247
  function getHorizontalAlignmentIcon(env) {
78163
78248
  const horizontalAlign = getHorizontalAlign(env);
78164
78249
  switch (horizontalAlign) {
@@ -78193,19 +78278,19 @@ function getWrapModeIcon(env) {
78193
78278
  }
78194
78279
  }
78195
78280
  function getRotationIcon(env) {
78196
- const rotation = getRotation(env);
78197
- switch (rotation) {
78198
- case Math.PI / 2:
78199
- return "o-spreadsheet-Icon.ROTATION-90";
78200
- case -Math.PI / 2:
78201
- return "o-spreadsheet-Icon.ROTATION-270";
78202
- case Math.PI / 4:
78203
- return "o-spreadsheet-Icon.ROTATION-45";
78204
- case -Math.PI / 4:
78205
- return "o-spreadsheet-Icon.ROTATION-315";
78206
- default:
78207
- return "o-spreadsheet-Icon.ROTATION-0";
78281
+ if (currentRotationEqual(env, Math.PI / 2)) {
78282
+ return "o-spreadsheet-Icon.ROTATION-90";
78283
+ }
78284
+ else if (currentRotationEqual(env, -Math.PI / 2)) {
78285
+ return "o-spreadsheet-Icon.ROTATION-270";
78286
+ }
78287
+ else if (currentRotationEqual(env, Math.PI / 4)) {
78288
+ return "o-spreadsheet-Icon.ROTATION-45";
78208
78289
  }
78290
+ else if (currentRotationEqual(env, -Math.PI / 4)) {
78291
+ return "o-spreadsheet-Icon.ROTATION-315";
78292
+ }
78293
+ return "o-spreadsheet-Icon.ROTATION-0";
78209
78294
  }
78210
78295
 
78211
78296
  const colMenuRegistry = new MenuItemRegistry();
@@ -86417,6 +86502,12 @@ class FindAndReplaceStore extends SpreadsheetStore {
86417
86502
  case "ACTIVATE_SHEET":
86418
86503
  this.isSearchDirty = true;
86419
86504
  this.shouldFinalizeUpdateSelection = true;
86505
+ if (this.searchOptions.specificRange) {
86506
+ this.searchOptions.specificRange = {
86507
+ ...this.searchOptions.specificRange,
86508
+ sheetId: this.getters.getActiveSheetId(),
86509
+ };
86510
+ }
86420
86511
  break;
86421
86512
  case "REPLACE_SEARCH":
86422
86513
  for (const match of cmd.matches) {
@@ -86803,9 +86894,20 @@ class FindAndReplacePanel extends Component {
86803
86894
  const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
86804
86895
  this.store.updateSearchOptions({ specificRange });
86805
86896
  }
86897
+ get specificRange() {
86898
+ const range = this.store.searchOptions.specificRange;
86899
+ return range ? this.env.model.getters.getRangeString(range, "forceSheetReference") : "";
86900
+ }
86806
86901
  get pendingSearch() {
86807
86902
  return this.updateSearchContent.isDebouncePending();
86808
86903
  }
86904
+ get selectionInputKey() {
86905
+ // Selections input are made to work with objects linked to a sheet id. They store the active sheet id at their creation,
86906
+ // and have specific behaviour linked to it (eg. go back to the initial sheet after confirmation).
86907
+ // We don't want all those behaviors here, so we force the recreation of the component when the active sheet changes.
86908
+ // The only drawback is that the input loses focus when changing sheet.
86909
+ return this.env.model.getters.getActiveSheetId();
86910
+ }
86809
86911
  }
86810
86912
 
86811
86913
  /**
@@ -97930,6 +98032,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
97930
98032
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DEFAULT_LOCALE, DEFAULT_LOCALES, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry$1 as Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, categories, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, createAutocompleteArgumentsProvider, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse$1 as parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
97931
98033
 
97932
98034
 
97933
- __info__.version = "19.1.2";
97934
- __info__.date = "2026-01-07T16:21:36.757Z";
97935
- __info__.hash = "febc3e9";
98035
+ __info__.version = "19.1.3";
98036
+ __info__.date = "2026-01-14T10:02:32.431Z";
98037
+ __info__.hash = "52a3e52";