@odoo/o-spreadsheet 19.0.12 → 19.0.15

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.0.12
6
- * @date 2025-12-02T05:34:17.495Z
7
- * @hash 32203f1
5
+ * @version 19.0.15
6
+ * @date 2025-12-26T10:19:23.408Z
7
+ * @hash fe625c9
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';
@@ -1893,21 +1893,25 @@ profilesStartingPosition, profiles, zones, toRemove = false) {
1893
1893
  function profilesContainsZone(profilesStartingPosition, profiles, zone) {
1894
1894
  const leftValue = zone.left;
1895
1895
  const rightValue = zone.right;
1896
- const topValue = zone.top;
1897
- const bottomValue = zone.bottom + 1;
1898
1896
  const leftIndex = binaryPredecessorSearch(profilesStartingPosition, leftValue, 0);
1899
- const rightIndex = binaryPredecessorSearch(profilesStartingPosition, rightValue, leftIndex);
1900
- if (leftIndex === -1 || rightIndex === -1) {
1901
- return false;
1902
- }
1897
+ const rightIndex = rightValue === undefined
1898
+ ? profilesStartingPosition.length - 1
1899
+ : binaryPredecessorSearch(profilesStartingPosition, rightValue, leftIndex);
1900
+ /**
1901
+ * The `profilesStartingPosition` array always contains at least the value `0` at its first position,
1902
+ * ensuring that applying `binaryPredecessorSearch` will always return a valid index.
1903
+ * Therefore, it is not necessary to check if the result of `binaryPredecessorSearch` equals `-1`.
1904
+ */
1905
+ const topValue = zone.top;
1906
+ const bottomValue = zone.bottom === undefined ? undefined : zone.bottom + 1;
1903
1907
  for (let i = leftIndex; i <= rightIndex; i++) {
1904
1908
  const profile = profiles.get(profilesStartingPosition[i]);
1905
- const topPredIndex = binaryPredecessorSearch(profile, topValue, 0, true);
1906
- const bottomSuccIndex = binarySuccessorSearch(profile, bottomValue, 0, true);
1909
+ const topPredIndex = binaryPredecessorSearch(profile, topValue, 0);
1907
1910
  if (topPredIndex === -1 || topPredIndex % 2 !== 0) {
1908
1911
  return false;
1909
1912
  }
1910
- if (topValue < profile[topPredIndex] || bottomValue > profile[bottomSuccIndex]) {
1913
+ const bottomSuccIndex = bottomValue === undefined ? profile.length : binarySuccessorSearch(profile, bottomValue, 0);
1914
+ if (topPredIndex + 1 !== bottomSuccIndex) {
1911
1915
  return false;
1912
1916
  }
1913
1917
  }
@@ -6593,17 +6597,41 @@ function toCriterionDateNumber(dateValue) {
6593
6597
  const today = DateTime.now();
6594
6598
  switch (dateValue) {
6595
6599
  case "today":
6596
- return jsDateToNumber(today);
6597
- case "yesterday":
6598
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
6599
- case "tomorrow":
6600
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
6600
+ return Math.floor(jsDateToNumber(today));
6601
+ case "yesterday": {
6602
+ today.setDate(today.getDate() - 1);
6603
+ return Math.floor(jsDateToNumber(today));
6604
+ }
6605
+ case "tomorrow": {
6606
+ today.setDate(today.getDate() + 1);
6607
+ return Math.floor(jsDateToNumber(today));
6608
+ }
6601
6609
  case "lastWeek":
6602
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
6603
- case "lastMonth":
6604
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
6610
+ today.setDate(today.getDate() - 6);
6611
+ return Math.floor(jsDateToNumber(today));
6612
+ case "lastMonth": {
6613
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
6614
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
6615
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
6616
+ today.setDate(1);
6617
+ }
6618
+ else {
6619
+ today.setDate(today.getDate() + 1);
6620
+ today.setMonth(today.getMonth() - 1);
6621
+ }
6622
+ return Math.floor(jsDateToNumber(today));
6623
+ }
6605
6624
  case "lastYear":
6606
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
6625
+ // Handle leap year case
6626
+ if (today.getMonth() === 1 && today.getDate() === 29) {
6627
+ today.setDate(28);
6628
+ today.setFullYear(today.getFullYear() - 1);
6629
+ }
6630
+ else {
6631
+ today.setDate(today.getDate() + 1);
6632
+ today.setFullYear(today.getFullYear() - 1);
6633
+ }
6634
+ return Math.floor(jsDateToNumber(today));
6607
6635
  }
6608
6636
  }
6609
6637
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -6776,67 +6804,6 @@ function getFullReference(sheetName, xc) {
6776
6804
  return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
6777
6805
  }
6778
6806
 
6779
- function createDefaultRows(rowNumber) {
6780
- const rows = [];
6781
- for (let i = 0; i < rowNumber; i++) {
6782
- const row = {
6783
- cells: {},
6784
- };
6785
- rows.push(row);
6786
- }
6787
- return rows;
6788
- }
6789
- function moveHeaderIndexesOnHeaderAddition(indexHeaderAdded, numberAdded, headers) {
6790
- return headers.map((header) => {
6791
- if (header >= indexHeaderAdded) {
6792
- return header + numberAdded;
6793
- }
6794
- return header;
6795
- });
6796
- }
6797
- function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
6798
- deletedHeaders = [...deletedHeaders].sort((a, b) => b - a);
6799
- return headers
6800
- .map((header) => {
6801
- for (const deletedHeader of deletedHeaders) {
6802
- if (header > deletedHeader) {
6803
- header--;
6804
- }
6805
- else if (header === deletedHeader) {
6806
- return undefined;
6807
- }
6808
- }
6809
- return header;
6810
- })
6811
- .filter(isDefined);
6812
- }
6813
- function getNextSheetName(existingNames, baseName = "Sheet") {
6814
- let i = 1;
6815
- let name = `${baseName}${i}`;
6816
- while (existingNames.includes(name)) {
6817
- name = `${baseName}${i}`;
6818
- i++;
6819
- }
6820
- return name;
6821
- }
6822
- function getDuplicateSheetName(nameToDuplicate, existingNames) {
6823
- let i = 1;
6824
- const baseName = _t("Copy of %s", nameToDuplicate);
6825
- let name = baseName.toString();
6826
- while (existingNames.includes(name)) {
6827
- name = `${baseName} (${i})`;
6828
- i++;
6829
- }
6830
- return name;
6831
- }
6832
- function isSheetNameEqual(name1, name2) {
6833
- if (name1 === undefined || name2 === undefined) {
6834
- return false;
6835
- }
6836
- return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
6837
- getUnquotedSheetName(name2.trim().toUpperCase()));
6838
- }
6839
-
6840
6807
  function createRange(args, getSheetSize) {
6841
6808
  const unboundedZone = args.zone;
6842
6809
  const zone = boundUnboundedZone(unboundedZone, getSheetSize(args.sheetId));
@@ -7084,7 +7051,7 @@ function getApplyRangeChangeRemoveColRow(cmd) {
7084
7051
  elements.sort((a, b) => b - a);
7085
7052
  const groups = groupConsecutive(elements);
7086
7053
  return (range) => {
7087
- if (!isSheetNameEqual(range.sheetId, cmd.sheetId)) {
7054
+ if (range.sheetId !== cmd.sheetId) {
7088
7055
  return { changeType: "NONE" };
7089
7056
  }
7090
7057
  let newRange = range;
@@ -7291,6 +7258,69 @@ function fuzzyLookup(pattern, list, fn) {
7291
7258
  return results.map((r) => r.elem);
7292
7259
  }
7293
7260
 
7261
+ function createDefaultRows(rowNumber) {
7262
+ const rows = [];
7263
+ for (let i = 0; i < rowNumber; i++) {
7264
+ const row = {
7265
+ cells: {},
7266
+ };
7267
+ rows.push(row);
7268
+ }
7269
+ return rows;
7270
+ }
7271
+ function moveHeaderIndexesOnHeaderAddition(indexHeaderAdded, numberAdded, headers) {
7272
+ return headers.map((header) => {
7273
+ if (header >= indexHeaderAdded) {
7274
+ return header + numberAdded;
7275
+ }
7276
+ return header;
7277
+ });
7278
+ }
7279
+ function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
7280
+ deletedHeaders = [...deletedHeaders].sort((a, b) => b - a);
7281
+ return headers
7282
+ .map((header) => {
7283
+ for (const deletedHeader of deletedHeaders) {
7284
+ if (header > deletedHeader) {
7285
+ header--;
7286
+ }
7287
+ else if (header === deletedHeader) {
7288
+ return undefined;
7289
+ }
7290
+ }
7291
+ return header;
7292
+ })
7293
+ .filter(isDefined);
7294
+ }
7295
+ function getNextSheetName(existingNames, baseName = "Sheet") {
7296
+ let i = 1;
7297
+ let name = `${baseName}${i}`;
7298
+ while (existingNames.includes(name)) {
7299
+ name = `${baseName}${i}`;
7300
+ i++;
7301
+ }
7302
+ return name;
7303
+ }
7304
+ function getDuplicateSheetName(nameToDuplicate, existingNames) {
7305
+ let i = 1;
7306
+ const baseName = _t("Copy of %s", nameToDuplicate);
7307
+ let name = baseName.toString();
7308
+ while (existingNames.includes(name)) {
7309
+ name = `${baseName} (${i})`;
7310
+ i++;
7311
+ }
7312
+ return name;
7313
+ }
7314
+ const toStandardizedSheetName = memoize(function toStandardizedSheetName(name) {
7315
+ return getUnquotedSheetName(name.trim().toUpperCase());
7316
+ });
7317
+ function isSheetNameEqual(name1, name2) {
7318
+ if (name1 === undefined || name2 === undefined) {
7319
+ return false;
7320
+ }
7321
+ return toStandardizedSheetName(name1) === toStandardizedSheetName(name2);
7322
+ }
7323
+
7294
7324
  function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
7295
7325
  return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
7296
7326
  }
@@ -31419,7 +31449,7 @@ function escapeQueryNameSpaces(query) {
31419
31449
  return query.replaceAll(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "NAMESPACE" + "$1" + "NAMESPACE" + "$2");
31420
31450
  }
31421
31451
 
31422
- function getChartMenuActions(figureId, onFigureDeleted, env) {
31452
+ function getChartMenuActions(figureId, env) {
31423
31453
  const chartId = env.model.getters.getChartIdFromFigureId(figureId);
31424
31454
  if (!chartId) {
31425
31455
  return [];
@@ -31439,11 +31469,11 @@ function getChartMenuActions(figureId, onFigureDeleted, env) {
31439
31469
  getCutMenuItem(figureId, env),
31440
31470
  getCopyAsImageMenuItem(figureId, env),
31441
31471
  getDownloadChartMenuItem(figureId, env),
31442
- getDeleteMenuItem(figureId, onFigureDeleted, env),
31472
+ getDeleteMenuItem(figureId, env),
31443
31473
  ];
31444
31474
  return createActions(menuItemSpecs).filter((action) => env.model.getters.isReadonly() ? action.isReadonlyAllowed : true);
31445
31475
  }
31446
- function getImageMenuActions(figureId, onFigureDeleted, env) {
31476
+ function getImageMenuActions(figureId, env) {
31447
31477
  const menuItemSpecs = [
31448
31478
  getCopyMenuItem(figureId, env, _t("Image copied to clipboard")),
31449
31479
  getCutMenuItem(figureId, env),
@@ -31486,11 +31516,11 @@ function getImageMenuActions(figureId, onFigureDeleted, env) {
31486
31516
  },
31487
31517
  icon: "o-spreadsheet-Icon.DOWNLOAD",
31488
31518
  },
31489
- getDeleteMenuItem(figureId, onFigureDeleted, env),
31519
+ getDeleteMenuItem(figureId, env),
31490
31520
  ];
31491
31521
  return createActions(menuItemSpecs);
31492
31522
  }
31493
- function getCarouselMenuActions(figureId, onFigureDeleted, env) {
31523
+ function getCarouselMenuActions(figureId, env) {
31494
31524
  const isChartSelected = (env) => env.model.getters.getSelectedCarouselItem(figureId)?.type === "chart";
31495
31525
  const menuItemSpecs = [
31496
31526
  {
@@ -31509,7 +31539,7 @@ function getCarouselMenuActions(figureId, onFigureDeleted, env) {
31509
31539
  },
31510
31540
  { ...getCutMenuItem(figureId, env), name: _t("Cut carousel") },
31511
31541
  {
31512
- ...getDeleteMenuItem(figureId, onFigureDeleted, env),
31542
+ ...getDeleteMenuItem(figureId, env),
31513
31543
  name: _t("Delete carousel"),
31514
31544
  separator: true,
31515
31545
  },
@@ -31652,7 +31682,7 @@ function getDownloadChartMenuItem(figureId, env) {
31652
31682
  isReadonlyAllowed: true,
31653
31683
  };
31654
31684
  }
31655
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
31685
+ function getDeleteMenuItem(figureId, env) {
31656
31686
  return {
31657
31687
  id: "delete",
31658
31688
  name: _t("Delete"),
@@ -31661,7 +31691,6 @@ function getDeleteMenuItem(figureId, onFigureDeleted, env) {
31661
31691
  sheetId: env.model.getters.getActiveSheetId(),
31662
31692
  figureId,
31663
31693
  });
31664
- onFigureDeleted();
31665
31694
  },
31666
31695
  icon: "o-spreadsheet-Icon.TRASH",
31667
31696
  };
@@ -32474,7 +32503,7 @@ class ChartDashboardMenu extends Component {
32474
32503
  this.menuState.isOpen = true;
32475
32504
  this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
32476
32505
  const figureId = this.env.model.getters.getFigureIdFromChartId(this.props.chartId);
32477
- this.menuState.menuItems = getChartMenuActions(figureId, () => { }, this.env);
32506
+ this.menuState.menuItems = getChartMenuActions(figureId, this.env);
32478
32507
  }
32479
32508
  get fullScreenMenuItem() {
32480
32509
  if (!this.props.hasFullScreenButton) {
@@ -32501,7 +32530,6 @@ class CarouselFigure extends Component {
32501
32530
  static template = "o-spreadsheet-CarouselFigure";
32502
32531
  static props = {
32503
32532
  figureUI: Object,
32504
- onFigureDeleted: Function,
32505
32533
  editFigureStyle: { type: Function, optional: true },
32506
32534
  isFullScreen: { type: Boolean, optional: true },
32507
32535
  openContextMenu: { type: Function, optional: true },
@@ -32650,7 +32678,6 @@ class ChartFigure extends Component {
32650
32678
  static template = "o-spreadsheet-ChartFigure";
32651
32679
  static props = {
32652
32680
  figureUI: Object,
32653
- onFigureDeleted: Function,
32654
32681
  editFigureStyle: { type: Function, optional: true },
32655
32682
  isFullScreen: { type: Boolean, optional: true },
32656
32683
  openContextMenu: { type: Function, optional: true },
@@ -32684,7 +32711,6 @@ class ImageFigure extends Component {
32684
32711
  static template = "o-spreadsheet-ImageFigure";
32685
32712
  static props = {
32686
32713
  figureUI: Object,
32687
- onFigureDeleted: Function,
32688
32714
  editFigureStyle: { type: Function, optional: true },
32689
32715
  openContextMenu: { type: Function, optional: true },
32690
32716
  };
@@ -32803,13 +32829,11 @@ class FigureComponent extends Component {
32803
32829
  figureUI: Object,
32804
32830
  style: { type: String, optional: true },
32805
32831
  class: { type: String, optional: true },
32806
- onFigureDeleted: { type: Function, optional: true },
32807
32832
  onMouseDown: { type: Function, optional: true },
32808
32833
  onClickAnchor: { type: Function, optional: true },
32809
32834
  };
32810
32835
  static components = { MenuPopover };
32811
32836
  static defaultProps = {
32812
- onFigureDeleted: () => { },
32813
32837
  onMouseDown: () => { },
32814
32838
  onClickAnchor: () => { },
32815
32839
  };
@@ -32887,9 +32911,6 @@ class FigureComponent extends Component {
32887
32911
  this.props.figureUI.id,
32888
32912
  this.figureRef.el,
32889
32913
  ]);
32890
- onWillUnmount(() => {
32891
- this.props.onFigureDeleted();
32892
- });
32893
32914
  }
32894
32915
  clickAnchor(dirX, dirY, ev) {
32895
32916
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -32913,7 +32934,6 @@ class FigureComponent extends Component {
32913
32934
  sheetId: this.env.model.getters.getActiveSheetId(),
32914
32935
  figureId: this.props.figureUI.id,
32915
32936
  });
32916
- this.props.onFigureDeleted();
32917
32937
  ev.preventDefault();
32918
32938
  ev.stopPropagation();
32919
32939
  break;
@@ -33006,7 +33026,7 @@ class FigureComponent extends Component {
33006
33026
  this.menuState.anchorRect = anchorRect;
33007
33027
  this.menuState.menuItems = figureRegistry
33008
33028
  .get(this.props.figureUI.tag)
33009
- .menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
33029
+ .menuBuilder(this.props.figureUI.id, this.env);
33010
33030
  }
33011
33031
  editWrapperStyle(properties) {
33012
33032
  if (this.figureWrapperRef.el) {
@@ -33378,7 +33398,7 @@ criterionEvaluatorRegistry.add("dateIs", {
33378
33398
  return false;
33379
33399
  }
33380
33400
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
33381
- const today = jsDateToRoundNumber(DateTime.now());
33401
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
33382
33402
  return isDateBetween(dateValue, today, criterionValue);
33383
33403
  }
33384
33404
  return areDatesSameDay(dateValue, criterionValue);
@@ -37492,6 +37512,12 @@ class SelectionInput extends Component {
37492
37512
  }
37493
37513
  setup() {
37494
37514
  useEffect(() => this.focusedInput.el?.focus(), () => [this.focusedInput.el]);
37515
+ useEffect(() => {
37516
+ // Check the offsetParent to know if the input or an ancestor is `display: none` (eg. when changing side panel tab)
37517
+ if (this.store.hasFocus && this.selectionRef.el?.offsetParent === null) {
37518
+ this.reset();
37519
+ }
37520
+ });
37495
37521
  this.store = useLocalStore(SelectionInputStore, this.props.ranges, this.props.hasSingleRange || false, this.props.colors, this.props.disabledRanges);
37496
37522
  onWillUpdateProps((nextProps) => {
37497
37523
  if (nextProps.ranges.join() !== this.store.selectionInputValues.join()) {
@@ -45275,7 +45301,7 @@ class FormulaFingerprintStore extends SpreadsheetStore {
45275
45301
  const leftOffset = isLeftUnbounded || left?.colFixed ? 0 : colCellOffset;
45276
45302
  const topOffset = isTopUnbounded || left?.rowFixed ? 0 : rowCellOffset;
45277
45303
  const isRightFixed = (!right && left?.colFixed) || right?.colFixed;
45278
- const isBottomFixed = (!right && left.rowFixed) || right?.rowFixed;
45304
+ const isBottomFixed = (!right && left?.rowFixed) || right?.rowFixed;
45279
45305
  const isRightUnbounded = range.unboundedZone.right === undefined;
45280
45306
  const isBottomUnbounded = range.unboundedZone.bottom === undefined;
45281
45307
  const rightOffset = isRightUnbounded || isRightFixed ? 0 : colCellOffset;
@@ -47839,7 +47865,37 @@ pivotRegistry.add("SPREADSHEET", {
47839
47865
  isMeasureCandidate: (field) => field.type !== "boolean",
47840
47866
  isGroupable: () => true,
47841
47867
  canHaveCustomGroup: (field) => field.type === "char" && !field.isCustomField,
47868
+ adaptRanges: (getters, definition, applyChange) => {
47869
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
47870
+ return definition;
47871
+ }
47872
+ const { sheetId, zone } = definition.dataSet;
47873
+ const range = getters.getRangeFromZone(sheetId, zone);
47874
+ const adaptedRange = adaptPivotRange(range, applyChange);
47875
+ if (adaptedRange === range) {
47876
+ return definition;
47877
+ }
47878
+ const dataSet = adaptedRange && {
47879
+ sheetId: adaptedRange.sheetId,
47880
+ zone: adaptedRange.zone,
47881
+ };
47882
+ return { ...definition, dataSet };
47883
+ },
47842
47884
  });
47885
+ function adaptPivotRange(range, applyChange) {
47886
+ if (!range) {
47887
+ return undefined;
47888
+ }
47889
+ const change = applyChange(range);
47890
+ switch (change.changeType) {
47891
+ case "NONE":
47892
+ return range;
47893
+ case "REMOVE":
47894
+ return undefined;
47895
+ default:
47896
+ return change.range;
47897
+ }
47898
+ }
47843
47899
 
47844
47900
  const pivotProperties = {
47845
47901
  name: _t("See pivot properties"),
@@ -49110,7 +49166,6 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
49110
49166
  }
49111
49167
  get highlights() {
49112
49168
  const position = this.model.getters.getActivePosition();
49113
- const cell = this.getters.getEvaluatedCell(position);
49114
49169
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
49115
49170
  const zone = spreader
49116
49171
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
@@ -49118,10 +49173,11 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
49118
49173
  if (!zone) {
49119
49174
  return [];
49120
49175
  }
49176
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
49121
49177
  return [
49122
49178
  {
49123
49179
  range: this.model.getters.getRangeFromZone(position.sheetId, zone),
49124
- dashed: cell.value === CellErrorType.SpilledBlocked,
49180
+ dashed: isArrayFormulaBlocked,
49125
49181
  color: "#17A2B8",
49126
49182
  noFill: true,
49127
49183
  thinLine: true,
@@ -50528,9 +50584,7 @@ css /*SCSS*/ `
50528
50584
  */
50529
50585
  class FiguresContainer extends Component {
50530
50586
  static template = "o-spreadsheet-FiguresContainer";
50531
- static props = {
50532
- onFigureDeleted: Function,
50533
- };
50587
+ static props = {};
50534
50588
  static components = { FigureComponent };
50535
50589
  dnd = useState({
50536
50590
  draggedFigure: undefined,
@@ -50740,7 +50794,6 @@ class FiguresContainer extends Component {
50740
50794
  carouselFigureId: this.dnd.overlappingCarousel.id,
50741
50795
  chartFigureId: figureUI.id,
50742
50796
  });
50743
- this.props.onFigureDeleted();
50744
50797
  }
50745
50798
  this.dnd.draggedFigure = undefined;
50746
50799
  this.dnd.horizontalSnap = undefined;
@@ -50966,16 +51019,16 @@ css /* scss */ `
50966
51019
  `;
50967
51020
  class GridAddRowsFooter extends Component {
50968
51021
  static template = "o-spreadsheet-GridAddRowsFooter";
50969
- static props = {
50970
- focusGrid: Function,
50971
- };
51022
+ static props = {};
50972
51023
  static components = { ValidationMessages };
51024
+ DOMFocusableElementStore;
50973
51025
  inputRef = useRef("inputRef");
50974
51026
  state = useState({
50975
51027
  inputValue: "100",
50976
51028
  errorFlag: false,
50977
51029
  });
50978
51030
  setup() {
51031
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
50979
51032
  useExternalListener(window, "click", this.onExternalClick, { capture: true });
50980
51033
  }
50981
51034
  get addRowsPosition() {
@@ -50993,7 +51046,7 @@ class GridAddRowsFooter extends Component {
50993
51046
  }
50994
51047
  onKeydown(ev) {
50995
51048
  if (ev.key.toUpperCase() === "ESCAPE") {
50996
- this.props.focusGrid();
51049
+ this.focusDefaultElement();
50997
51050
  }
50998
51051
  else if (ev.key.toUpperCase() === "ENTER") {
50999
51052
  this.onConfirm();
@@ -51020,7 +51073,7 @@ class GridAddRowsFooter extends Component {
51020
51073
  quantity,
51021
51074
  dimension: "ROW",
51022
51075
  });
51023
- this.props.focusGrid();
51076
+ this.focusDefaultElement();
51024
51077
  // After adding new rows, scroll down to the new last row
51025
51078
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
51026
51079
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -51033,7 +51086,12 @@ class GridAddRowsFooter extends Component {
51033
51086
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
51034
51087
  return;
51035
51088
  }
51036
- this.props.focusGrid();
51089
+ this.focusDefaultElement();
51090
+ }
51091
+ focusDefaultElement() {
51092
+ if (document.activeElement === this.inputRef.el) {
51093
+ this.DOMFocusableElementStore.focus();
51094
+ }
51037
51095
  }
51038
51096
  }
51039
51097
 
@@ -51308,7 +51366,6 @@ class GridOverlay extends Component {
51308
51366
  onCellClicked: { type: Function, optional: true },
51309
51367
  onCellRightClicked: { type: Function, optional: true },
51310
51368
  onGridResized: { type: Function, optional: true },
51311
- onFigureDeleted: { type: Function, optional: true },
51312
51369
  onGridMoved: Function,
51313
51370
  gridOverlayDimensions: String,
51314
51371
  slots: { type: Object, optional: true },
@@ -51323,7 +51380,6 @@ class GridOverlay extends Component {
51323
51380
  onCellClicked: () => { },
51324
51381
  onCellRightClicked: () => { },
51325
51382
  onGridResized: () => { },
51326
- onFigureDeleted: () => { },
51327
51383
  };
51328
51384
  gridOverlay = useRef("gridOverlay");
51329
51385
  cellPopovers;
@@ -56589,7 +56645,7 @@ function useHighlights(highlightProvider) {
56589
56645
  }
56590
56646
 
56591
56647
  css /* scss */ `
56592
- .o-cf-preview {
56648
+ .o-spreadsheet .o-cf-preview {
56593
56649
  &.o-cf-cursor-ptr {
56594
56650
  cursor: pointer;
56595
56651
  }
@@ -56597,6 +56653,7 @@ css /* scss */ `
56597
56653
  border-bottom: 1px solid ${GRAY_300};
56598
56654
  height: 80px;
56599
56655
  padding: 10px;
56656
+ box-sizing: border-box;
56600
56657
  position: relative;
56601
56658
  cursor: pointer;
56602
56659
  &:hover,
@@ -56610,7 +56667,6 @@ css /* scss */ `
56610
56667
  .o-cf-preview-icon {
56611
56668
  border: 1px solid ${GRAY_300};
56612
56669
  background-color: #fff;
56613
- position: absolute;
56614
56670
  height: 50px;
56615
56671
  width: 50px;
56616
56672
  .o-icon {
@@ -56619,12 +56675,6 @@ css /* scss */ `
56619
56675
  }
56620
56676
  }
56621
56677
  .o-cf-preview-description {
56622
- left: 65px;
56623
- margin-bottom: auto;
56624
- margin-right: 8px;
56625
- margin-top: auto;
56626
- position: relative;
56627
- width: 142px;
56628
56678
  .o-cf-preview-description-rule {
56629
56679
  margin-bottom: 4px;
56630
56680
  max-height: 2.8em;
@@ -56634,16 +56684,11 @@ css /* scss */ `
56634
56684
  font-size: 12px;
56635
56685
  }
56636
56686
  }
56637
- .o-cf-delete {
56638
- left: 90%;
56639
- top: 39%;
56640
- position: absolute;
56641
- }
56642
56687
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
56643
56688
  display: none !important;
56644
56689
  }
56645
56690
  .o-cf-drag-handle {
56646
- left: -8px;
56691
+ left: 2px;
56647
56692
  cursor: move;
56648
56693
  .o-icon {
56649
56694
  width: 6px;
@@ -62448,10 +62493,10 @@ class BordersPlugin extends CorePlugin {
62448
62493
  // existingBorderSideToClear[side] = true means we should clear the border on that
62449
62494
  // side of the existing adjacent zone before adding the new border.
62450
62495
  const existingBorderSideToClear = {
62451
- left: force || !!newBorder?.right,
62452
- right: force || !!newBorder?.left,
62453
- top: force || !!newBorder?.bottom,
62454
- bottom: force || !!newBorder?.top,
62496
+ left: !!newBorder?.right,
62497
+ right: !!newBorder?.left,
62498
+ top: !!newBorder?.bottom,
62499
+ bottom: !!newBorder?.top,
62455
62500
  };
62456
62501
  let editingZone = [zone];
62457
62502
  for (const existingBorder of this.borders[sheetId] ?? []) {
@@ -65444,6 +65489,7 @@ function rangeToMerge(mergeId, range) {
65444
65489
  class RangeAdapter {
65445
65490
  getters;
65446
65491
  providers = [];
65492
+ isAdaptingRanges = false;
65447
65493
  constructor(getters) {
65448
65494
  this.getters = getters;
65449
65495
  }
@@ -65475,6 +65521,9 @@ class RangeAdapter {
65475
65521
  }
65476
65522
  beforeHandle(command) { }
65477
65523
  handle(cmd) {
65524
+ if (this.isAdaptingRanges) {
65525
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
65526
+ }
65478
65527
  const rangeAdapter = getRangeAdapter(cmd);
65479
65528
  if (rangeAdapter?.applyChange) {
65480
65529
  this.executeOnAllRanges(rangeAdapter.applyChange, rangeAdapter.sheetId, rangeAdapter.sheetName);
@@ -65497,10 +65546,12 @@ class RangeAdapter {
65497
65546
  };
65498
65547
  }
65499
65548
  executeOnAllRanges(adaptRange, sheetId, sheetName) {
65549
+ this.isAdaptingRanges = true;
65500
65550
  const func = this.verifyRangeRemoved(adaptRange);
65501
65551
  for (const provider of this.providers) {
65502
65552
  provider(func, sheetId, sheetName);
65503
65553
  }
65554
+ this.isAdaptingRanges = false;
65504
65555
  }
65505
65556
  /**
65506
65557
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -65817,7 +65868,7 @@ class SheetPlugin extends CorePlugin {
65817
65868
  break;
65818
65869
  case "CREATE_SHEET":
65819
65870
  const sheet = this.createSheet(cmd.sheetId, cmd.name || this.getNextSheetName(), cmd.cols || 26, cmd.rows || 100, cmd.position);
65820
- this.history.update("sheetIdsMapName", sheet.name, sheet.id);
65871
+ this.history.update("sheetIdsMapName", toStandardizedSheetName(sheet.name), sheet.id);
65821
65872
  break;
65822
65873
  case "MOVE_SHEET":
65823
65874
  this.moveSheet(cmd.sheetId, cmd.delta);
@@ -65884,7 +65935,7 @@ class SheetPlugin extends CorePlugin {
65884
65935
  // that depends on a sheet not already imported will not be able to be
65885
65936
  // compiled
65886
65937
  for (const sheet of data.sheets) {
65887
- this.sheetIdsMapName[sheet.name] = sheet.id;
65938
+ this.sheetIdsMapName[toStandardizedSheetName(sheet.name)] = sheet.id;
65888
65939
  }
65889
65940
  for (const sheetData of data.sheets) {
65890
65941
  const name = sheetData.name || "Sheet" + (Object.keys(this.sheets).length + 1);
@@ -65974,12 +66025,7 @@ class SheetPlugin extends CorePlugin {
65974
66025
  }
65975
66026
  getSheetIdByName(name) {
65976
66027
  if (name) {
65977
- const unquotedName = getUnquotedSheetName(name);
65978
- for (const key in this.sheetIdsMapName) {
65979
- if (isSheetNameEqual(key, unquotedName)) {
65980
- return this.sheetIdsMapName[key];
65981
- }
65982
- }
66028
+ return this.sheetIdsMapName[toStandardizedSheetName(name)];
65983
66029
  }
65984
66030
  return undefined;
65985
66031
  }
@@ -66279,8 +66325,8 @@ class SheetPlugin extends CorePlugin {
66279
66325
  const oldName = sheet.name;
66280
66326
  this.history.update("sheets", sheet.id, "name", name.trim());
66281
66327
  const sheetIdsMapName = Object.assign({}, this.sheetIdsMapName);
66282
- delete sheetIdsMapName[oldName];
66283
- sheetIdsMapName[name] = sheet.id;
66328
+ delete sheetIdsMapName[toStandardizedSheetName(oldName)];
66329
+ sheetIdsMapName[toStandardizedSheetName(name)] = sheet.id;
66284
66330
  this.history.update("sheetIdsMapName", sheetIdsMapName);
66285
66331
  }
66286
66332
  hideSheet(sheetId) {
@@ -66318,7 +66364,7 @@ class SheetPlugin extends CorePlugin {
66318
66364
  });
66319
66365
  }
66320
66366
  const sheetIdsMapName = Object.assign({}, this.sheetIdsMapName);
66321
- sheetIdsMapName[newSheet.name] = newSheet.id;
66367
+ sheetIdsMapName[toStandardizedSheetName(newSheet.name)] = newSheet.id;
66322
66368
  this.history.update("sheetIdsMapName", sheetIdsMapName);
66323
66369
  }
66324
66370
  getDuplicateSheetName(sheetName) {
@@ -66335,7 +66381,7 @@ class SheetPlugin extends CorePlugin {
66335
66381
  orderedSheetIds.splice(currentIndex, 1);
66336
66382
  this.history.update("orderedSheetIds", orderedSheetIds);
66337
66383
  const sheetIdsMapName = Object.assign({}, this.sheetIdsMapName);
66338
- delete sheetIdsMapName[name];
66384
+ delete sheetIdsMapName[toStandardizedSheetName(name)];
66339
66385
  this.history.update("sheetIdsMapName", sheetIdsMapName);
66340
66386
  }
66341
66387
  /**
@@ -67655,6 +67701,18 @@ class PivotCorePlugin extends CorePlugin {
67655
67701
  }
67656
67702
  }
67657
67703
  adaptRanges(applyChange) {
67704
+ for (const pivotId in this.pivots) {
67705
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
67706
+ if (!definition) {
67707
+ continue;
67708
+ }
67709
+ const newDefinition = pivotRegistry
67710
+ .get(definition.type)
67711
+ ?.adaptRanges?.(this.getters, definition, applyChange);
67712
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
67713
+ this.history.update("pivots", pivotId, "definition", newDefinition);
67714
+ }
67715
+ }
67658
67716
  for (const sheetId in this.compiledMeasureFormulas) {
67659
67717
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
67660
67718
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -67799,17 +67857,10 @@ class PivotCorePlugin extends CorePlugin {
67799
67857
  if (!pivot) {
67800
67858
  continue;
67801
67859
  }
67802
- const def = deepCopy(pivot.definition);
67803
- for (const measure of def.measures) {
67860
+ for (const measure of pivot.definition.measures) {
67804
67861
  if (measure.computedBy?.formula === formulaString) {
67805
- const measureIndex = def.measures.indexOf(measure);
67806
- if (measureIndex !== -1) {
67807
- def.measures[measureIndex].computedBy = {
67808
- formula: newFormulaString,
67809
- sheetId,
67810
- };
67811
- }
67812
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
67862
+ const measureIndex = pivot.definition.measures.indexOf(measure);
67863
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
67813
67864
  }
67814
67865
  }
67815
67866
  }
@@ -67936,20 +67987,6 @@ class SettingsPlugin extends CorePlugin {
67936
67987
  }
67937
67988
  }
67938
67989
 
67939
- function adaptPivotRange(range, applyChange) {
67940
- if (!range) {
67941
- return undefined;
67942
- }
67943
- const change = applyChange(range);
67944
- switch (change.changeType) {
67945
- case "NONE":
67946
- return range;
67947
- case "REMOVE":
67948
- return undefined;
67949
- default:
67950
- return change.range;
67951
- }
67952
- }
67953
67990
  class SpreadsheetPivotCorePlugin extends CorePlugin {
67954
67991
  allowDispatch(cmd) {
67955
67992
  switch (cmd.type) {
@@ -67960,27 +67997,6 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
67960
67997
  }
67961
67998
  return "Success" /* CommandResult.Success */;
67962
67999
  }
67963
- adaptRanges(applyChange) {
67964
- for (const pivotId of this.getters.getPivotIds()) {
67965
- const definition = this.getters.getPivotCoreDefinition(pivotId);
67966
- if (definition.type !== "SPREADSHEET") {
67967
- continue;
67968
- }
67969
- if (definition.dataSet) {
67970
- const { sheetId, zone } = definition.dataSet;
67971
- const range = this.getters.getRangeFromZone(sheetId, zone);
67972
- const adaptedRange = adaptPivotRange(range, applyChange);
67973
- if (adaptedRange === range) {
67974
- return;
67975
- }
67976
- const dataSet = adaptedRange && {
67977
- sheetId: adaptedRange.sheetId,
67978
- zone: adaptedRange.zone,
67979
- };
67980
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
67981
- }
67982
- }
67983
- }
67984
68000
  checkDataSetValidity(definition) {
67985
68001
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
67986
68002
  const { zone, sheetId } = definition.dataSet;
@@ -68979,13 +68995,6 @@ class ZoneSet {
68979
68995
  }
68980
68996
  return result;
68981
68997
  }
68982
- size() {
68983
- let size = 0;
68984
- for (const profile of this.profiles.values()) {
68985
- size += profile.length;
68986
- }
68987
- return size / 2;
68988
- }
68989
68998
  /**
68990
68999
  * iterator of all the zones in the ZoneSet
68991
69000
  */
@@ -69067,13 +69076,6 @@ class RangeSet {
69067
69076
  clear() {
69068
69077
  this.setsBySheetId = {};
69069
69078
  }
69070
- size() {
69071
- let size = 0;
69072
- for (const sheetId in this.setsBySheetId) {
69073
- size += this.setsBySheetId[sheetId].size();
69074
- }
69075
- return size;
69076
- }
69077
69079
  isEmpty() {
69078
69080
  for (const sheetId in this.setsBySheetId) {
69079
69081
  if (!this.setsBySheetId[sheetId].isEmpty()) {
@@ -69577,6 +69579,9 @@ class Evaluator {
69577
69579
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
69578
69580
  return arrayFormulas.find((position) => !this.blockedArrayFormulas.has(position));
69579
69581
  }
69582
+ isArrayFormulaSpillBlocked(position) {
69583
+ return this.blockedArrayFormulas.has(position);
69584
+ }
69580
69585
  updateDependencies(position) {
69581
69586
  // removing dependencies is slow because it requires
69582
69587
  // to traverse the entire r-tree.
@@ -69588,13 +69593,8 @@ class Evaluator {
69588
69593
  addDependencies(position, dependencies) {
69589
69594
  this.formulaDependencies().addDependencies(position, dependencies);
69590
69595
  for (const range of dependencies) {
69591
- const sheetId = range.sheetId;
69592
- const { left, bottom, right, top } = range.zone;
69593
- for (let col = left; col <= right; col++) {
69594
- for (let row = top; row <= bottom; row++) {
69595
- this.computeAndSave({ sheetId, col, row });
69596
- }
69597
- }
69596
+ // ensure that all ranges are computed
69597
+ this.compilationParams.ensureRange(range, false);
69598
69598
  }
69599
69599
  }
69600
69600
  updateCompilationParameters() {
@@ -69822,6 +69822,10 @@ class Evaluator {
69822
69822
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
69823
69823
  const nbColumns = formulaReturn.length;
69824
69824
  const nbRows = formulaReturn[0].length;
69825
+ if (nbRows === 0) {
69826
+ // empty matrix
69827
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
69828
+ }
69825
69829
  const resultZone = {
69826
69830
  top: formulaPosition.row,
69827
69831
  bottom: formulaPosition.row + nbRows - 1,
@@ -70092,6 +70096,7 @@ class EvaluationPlugin extends CoreViewPlugin {
70092
70096
  "getEvaluatedCellsPositions",
70093
70097
  "getSpreadZone",
70094
70098
  "getArrayFormulaSpreadingOn",
70099
+ "isArrayFormulaSpillBlocked",
70095
70100
  "isEmpty",
70096
70101
  ];
70097
70102
  shouldRebuildDependenciesGraph = true;
@@ -70211,6 +70216,9 @@ class EvaluationPlugin extends CoreViewPlugin {
70211
70216
  getArrayFormulaSpreadingOn(position) {
70212
70217
  return this.evaluator.getArrayFormulaSpreadingOn(position);
70213
70218
  }
70219
+ isArrayFormulaSpillBlocked(position) {
70220
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
70221
+ }
70214
70222
  /**
70215
70223
  * Check if a zone only contains empty cells
70216
70224
  */
@@ -84316,7 +84324,7 @@ class Spreadsheet extends Component {
84316
84324
  document.activeElement?.contains(this.spreadsheetRef.el)) {
84317
84325
  this.focusGrid();
84318
84326
  }
84319
- }, () => [this.env.model.getters.getActiveSheetId()]);
84327
+ });
84320
84328
  useExternalListener(window, "resize", () => this.render(true));
84321
84329
  // For some reason, the wheel event is not properly registered inside templates
84322
84330
  // in Chromium-based browsers based on chromium 125
@@ -89056,6 +89064,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
89056
89064
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
89057
89065
 
89058
89066
 
89059
- __info__.version = "19.0.12";
89060
- __info__.date = "2025-12-02T05:34:17.495Z";
89061
- __info__.hash = "32203f1";
89067
+ __info__.version = "19.0.15";
89068
+ __info__.date = "2025-12-26T10:19:23.408Z";
89069
+ __info__.hash = "fe625c9";