@odoo/o-spreadsheet 18.4.18 → 18.4.22

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 18.4.18
6
- * @date 2025-11-24T07:42:07.821Z
7
- * @hash 4f83667
5
+ * @version 18.4.22
6
+ * @date 2025-12-26T10:19:07.786Z
7
+ * @hash 6ddac00
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';
@@ -2613,7 +2613,6 @@ const invalidateEvaluationCommands = new Set([
2613
2613
  "REDO",
2614
2614
  "ADD_MERGE",
2615
2615
  "REMOVE_MERGE",
2616
- "DUPLICATE_SHEET",
2617
2616
  "UPDATE_LOCALE",
2618
2617
  "ADD_PIVOT",
2619
2618
  "UPDATE_PIVOT",
@@ -5214,17 +5213,41 @@ function toCriterionDateNumber(dateValue) {
5214
5213
  const today = DateTime.now();
5215
5214
  switch (dateValue) {
5216
5215
  case "today":
5217
- return jsDateToNumber(today);
5218
- case "yesterday":
5219
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
5220
- case "tomorrow":
5221
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
5216
+ return Math.floor(jsDateToNumber(today));
5217
+ case "yesterday": {
5218
+ today.setDate(today.getDate() - 1);
5219
+ return Math.floor(jsDateToNumber(today));
5220
+ }
5221
+ case "tomorrow": {
5222
+ today.setDate(today.getDate() + 1);
5223
+ return Math.floor(jsDateToNumber(today));
5224
+ }
5222
5225
  case "lastWeek":
5223
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
5224
- case "lastMonth":
5225
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
5226
+ today.setDate(today.getDate() - 6);
5227
+ return Math.floor(jsDateToNumber(today));
5228
+ case "lastMonth": {
5229
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
5230
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
5231
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
5232
+ today.setDate(1);
5233
+ }
5234
+ else {
5235
+ today.setDate(today.getDate() + 1);
5236
+ today.setMonth(today.getMonth() - 1);
5237
+ }
5238
+ return Math.floor(jsDateToNumber(today));
5239
+ }
5226
5240
  case "lastYear":
5227
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
5241
+ // Handle leap year case
5242
+ if (today.getMonth() === 1 && today.getDate() === 29) {
5243
+ today.setDate(28);
5244
+ today.setFullYear(today.getFullYear() - 1);
5245
+ }
5246
+ else {
5247
+ today.setDate(today.getDate() + 1);
5248
+ today.setFullYear(today.getFullYear() - 1);
5249
+ }
5250
+ return Math.floor(jsDateToNumber(today));
5228
5251
  }
5229
5252
  }
5230
5253
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -22582,6 +22605,9 @@ function getTreeMapGroupColors(definition, tree) {
22582
22605
  }));
22583
22606
  }
22584
22607
  function getTreeMapColorScale(tree, coloringOption) {
22608
+ if (tree.length === 0) {
22609
+ return undefined;
22610
+ }
22585
22611
  const treeNodesByLevel = pyramidizeTree(tree);
22586
22612
  const nodes = treeNodesByLevel[treeNodesByLevel.length - 1];
22587
22613
  const minValue = Math.min(...nodes.map((node) => node.value));
@@ -24251,11 +24277,18 @@ function chartToImageUrl(runtime, figure, type) {
24251
24277
  // we have to add the canvas to the DOM otherwise it won't be rendered
24252
24278
  document.body.append(div);
24253
24279
  if ("chartJsConfig" in runtime) {
24280
+ const extensionsLoaded = areChartJSExtensionsLoaded();
24281
+ if (!extensionsLoaded) {
24282
+ registerChartJSExtensions();
24283
+ }
24254
24284
  const config = deepCopy(runtime.chartJsConfig);
24255
24285
  config.plugins = [backgroundColorChartJSPlugin];
24256
24286
  const chart = new window.Chart(canvas, config);
24257
24287
  imageContent = chart.toBase64Image();
24258
24288
  chart.destroy();
24289
+ if (!extensionsLoaded) {
24290
+ unregisterChartJsExtensions();
24291
+ }
24259
24292
  }
24260
24293
  else if (type === "scorecard") {
24261
24294
  const design = getScorecardConfiguration(figure, runtime);
@@ -24285,11 +24318,18 @@ async function chartToImageFile(runtime, figure, type) {
24285
24318
  document.body.append(div);
24286
24319
  let chartBlob = null;
24287
24320
  if ("chartJsConfig" in runtime) {
24321
+ const extensionsLoaded = areChartJSExtensionsLoaded();
24322
+ if (!extensionsLoaded) {
24323
+ registerChartJSExtensions();
24324
+ }
24288
24325
  const config = deepCopy(runtime.chartJsConfig);
24289
24326
  config.plugins = [backgroundColorChartJSPlugin];
24290
24327
  const chart = new window.Chart(canvas, config);
24291
24328
  chartBlob = await new Promise((resolve) => canvas.toBlob(resolve, "image/png"));
24292
24329
  chart.destroy();
24330
+ if (!extensionsLoaded) {
24331
+ unregisterChartJsExtensions();
24332
+ }
24293
24333
  }
24294
24334
  else if (type === "scorecard") {
24295
24335
  const design = getScorecardConfiguration(figure, runtime);
@@ -29702,7 +29742,7 @@ function escapeQueryNameSpaces(query) {
29702
29742
  return query.replaceAll(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)/g, "NAMESPACE" + "$1" + "NAMESPACE" + "$2");
29703
29743
  }
29704
29744
 
29705
- function getChartMenuActions(figureId, onFigureDeleted, env) {
29745
+ function getChartMenuActions(figureId, env) {
29706
29746
  const menuItemSpecs = [
29707
29747
  {
29708
29748
  id: "edit",
@@ -29753,11 +29793,11 @@ function getChartMenuActions(figureId, onFigureDeleted, env) {
29753
29793
  },
29754
29794
  isReadonlyAllowed: true,
29755
29795
  },
29756
- getDeleteMenuItem(figureId, onFigureDeleted, env),
29796
+ getDeleteMenuItem(figureId, env),
29757
29797
  ];
29758
29798
  return createActions(menuItemSpecs).filter((action) => env.model.getters.isReadonly() ? action.isReadonlyAllowed : true);
29759
29799
  }
29760
- function getImageMenuActions(figureId, onFigureDeleted, env) {
29800
+ function getImageMenuActions(figureId, env) {
29761
29801
  const menuItemSpecs = [
29762
29802
  getCopyMenuItem(figureId, env, _t("Image copied to clipboard")),
29763
29803
  getCutMenuItem(figureId, env),
@@ -29802,7 +29842,7 @@ function getImageMenuActions(figureId, onFigureDeleted, env) {
29802
29842
  },
29803
29843
  icon: "o-spreadsheet-Icon.DOWNLOAD",
29804
29844
  },
29805
- getDeleteMenuItem(figureId, onFigureDeleted, env),
29845
+ getDeleteMenuItem(figureId, env),
29806
29846
  ];
29807
29847
  return createActions(menuItemSpecs);
29808
29848
  }
@@ -29838,7 +29878,7 @@ function getCutMenuItem(figureId, env) {
29838
29878
  icon: "o-spreadsheet-Icon.CUT",
29839
29879
  };
29840
29880
  }
29841
- function getDeleteMenuItem(figureId, onFigureDeleted, env) {
29881
+ function getDeleteMenuItem(figureId, env) {
29842
29882
  return {
29843
29883
  id: "delete",
29844
29884
  name: _t("Delete"),
@@ -29848,7 +29888,6 @@ function getDeleteMenuItem(figureId, onFigureDeleted, env) {
29848
29888
  sheetId: env.model.getters.getActiveSheetId(),
29849
29889
  figureId,
29850
29890
  });
29851
- onFigureDeleted();
29852
29891
  },
29853
29892
  icon: "o-spreadsheet-Icon.TRASH",
29854
29893
  };
@@ -30693,7 +30732,7 @@ class ChartDashboardMenu extends Component {
30693
30732
  openContextMenu(ev) {
30694
30733
  this.menuState.isOpen = true;
30695
30734
  this.menuState.anchorRect = getBoundingRectAsPOJO(ev.currentTarget);
30696
- this.menuState.menuItems = getChartMenuActions(this.props.figureUI.id, () => { }, this.env);
30735
+ this.menuState.menuItems = getChartMenuActions(this.props.figureUI.id, this.env);
30697
30736
  }
30698
30737
  get fullScreenMenuItem() {
30699
30738
  const definition = this.env.model.getters.getChartDefinition(this.props.figureUI.id);
@@ -30735,7 +30774,6 @@ class ChartFigure extends Component {
30735
30774
  static template = "o-spreadsheet-ChartFigure";
30736
30775
  static props = {
30737
30776
  figureUI: Object,
30738
- onFigureDeleted: Function,
30739
30777
  };
30740
30778
  static components = { ChartDashboardMenu };
30741
30779
  onDoubleClick() {
@@ -30759,7 +30797,6 @@ class ImageFigure extends Component {
30759
30797
  static template = "o-spreadsheet-ImageFigure";
30760
30798
  static props = {
30761
30799
  figureUI: Object,
30762
- onFigureDeleted: Function,
30763
30800
  };
30764
30801
  static components = {};
30765
30802
  // ---------------------------------------------------------------------------
@@ -30870,13 +30907,11 @@ class FigureComponent extends Component {
30870
30907
  static props = {
30871
30908
  figureUI: Object,
30872
30909
  style: { type: String, optional: true },
30873
- onFigureDeleted: { type: Function, optional: true },
30874
30910
  onMouseDown: { type: Function, optional: true },
30875
30911
  onClickAnchor: { type: Function, optional: true },
30876
30912
  };
30877
30913
  static components = { MenuPopover };
30878
30914
  static defaultProps = {
30879
- onFigureDeleted: () => { },
30880
30915
  onMouseDown: () => { },
30881
30916
  onClickAnchor: () => { },
30882
30917
  };
@@ -30953,9 +30988,6 @@ class FigureComponent extends Component {
30953
30988
  this.props.figureUI.id,
30954
30989
  this.figureRef.el,
30955
30990
  ]);
30956
- onWillUnmount(() => {
30957
- this.props.onFigureDeleted();
30958
- });
30959
30991
  }
30960
30992
  clickAnchor(dirX, dirY, ev) {
30961
30993
  this.props.onClickAnchor(dirX, dirY, ev);
@@ -30979,7 +31011,6 @@ class FigureComponent extends Component {
30979
31011
  sheetId: this.env.model.getters.getActiveSheetId(),
30980
31012
  figureId: this.props.figureUI.id,
30981
31013
  });
30982
- this.props.onFigureDeleted();
30983
31014
  ev.preventDefault();
30984
31015
  ev.stopPropagation();
30985
31016
  break;
@@ -31072,7 +31103,7 @@ class FigureComponent extends Component {
31072
31103
  this.menuState.anchorRect = anchorRect;
31073
31104
  this.menuState.menuItems = figureRegistry
31074
31105
  .get(this.props.figureUI.tag)
31075
- .menuBuilder(this.props.figureUI.id, this.props.onFigureDeleted, this.env);
31106
+ .menuBuilder(this.props.figureUI.id, this.env);
31076
31107
  }
31077
31108
  }
31078
31109
 
@@ -31437,7 +31468,7 @@ criterionEvaluatorRegistry.add("dateIs", {
31437
31468
  return false;
31438
31469
  }
31439
31470
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
31440
- const today = jsDateToRoundNumber(DateTime.now());
31471
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
31441
31472
  return isDateBetween(dateValue, today, criterionValue);
31442
31473
  }
31443
31474
  return areDatesSameDay(dateValue, criterionValue);
@@ -32642,7 +32673,7 @@ class AbstractComposerStore extends SpreadsheetStore {
32642
32673
  }
32643
32674
  this.selectionStart = start;
32644
32675
  this.selectionEnd = end;
32645
- this.editionMode = "editing";
32676
+ this.stopComposerRangeSelection();
32646
32677
  this.computeFormulaCursorContext();
32647
32678
  this.computeParenthesisRelatedToCursor();
32648
32679
  this.updateAutoCompleteProvider();
@@ -33547,7 +33578,8 @@ class Composer extends Component {
33547
33578
  assistantStyle["max-height"] = `${availableSpaceAbove - CLOSE_ICON_RADIUS}px`;
33548
33579
  // render top
33549
33580
  // We compensate 2 px of margin on the assistant style + 1px for design reasons
33550
- assistantStyle.transform = `translate(0, calc(-100% - ${cellHeight + 3}px))`;
33581
+ assistantStyle.top = `-3px`;
33582
+ assistantStyle.transform = `translate(0, -100%)`;
33551
33583
  }
33552
33584
  if (cellX + ASSISTANT_WIDTH > this.props.delimitation.width) {
33553
33585
  // render left
@@ -45238,7 +45270,6 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
45238
45270
  }
45239
45271
  get highlights() {
45240
45272
  const position = this.model.getters.getActivePosition();
45241
- const cell = this.getters.getEvaluatedCell(position);
45242
45273
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
45243
45274
  const zone = spreader
45244
45275
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
@@ -45246,10 +45277,11 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
45246
45277
  if (!zone) {
45247
45278
  return [];
45248
45279
  }
45280
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
45249
45281
  return [
45250
45282
  {
45251
45283
  range: this.model.getters.getRangeFromZone(position.sheetId, zone),
45252
- dashed: cell.value === CellErrorType.SpilledBlocked,
45284
+ dashed: isArrayFormulaBlocked,
45253
45285
  color: "#17A2B8",
45254
45286
  noFill: true,
45255
45287
  thinLine: true,
@@ -46347,9 +46379,7 @@ css /*SCSS*/ `
46347
46379
  */
46348
46380
  class FiguresContainer extends Component {
46349
46381
  static template = "o-spreadsheet-FiguresContainer";
46350
- static props = {
46351
- onFigureDeleted: Function,
46352
- };
46382
+ static props = {};
46353
46383
  static components = { FigureComponent };
46354
46384
  dnd = useState({
46355
46385
  draggedFigure: undefined,
@@ -46724,16 +46754,16 @@ css /* scss */ `
46724
46754
  `;
46725
46755
  class GridAddRowsFooter extends Component {
46726
46756
  static template = "o-spreadsheet-GridAddRowsFooter";
46727
- static props = {
46728
- focusGrid: Function,
46729
- };
46757
+ static props = {};
46730
46758
  static components = { ValidationMessages };
46759
+ DOMFocusableElementStore;
46731
46760
  inputRef = useRef("inputRef");
46732
46761
  state = useState({
46733
46762
  inputValue: "100",
46734
46763
  errorFlag: false,
46735
46764
  });
46736
46765
  setup() {
46766
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
46737
46767
  useExternalListener(window, "click", this.onExternalClick, { capture: true });
46738
46768
  }
46739
46769
  get addRowsPosition() {
@@ -46751,7 +46781,7 @@ class GridAddRowsFooter extends Component {
46751
46781
  }
46752
46782
  onKeydown(ev) {
46753
46783
  if (ev.key.toUpperCase() === "ESCAPE") {
46754
- this.props.focusGrid();
46784
+ this.focusDefaultElement();
46755
46785
  }
46756
46786
  else if (ev.key.toUpperCase() === "ENTER") {
46757
46787
  this.onConfirm();
@@ -46778,7 +46808,7 @@ class GridAddRowsFooter extends Component {
46778
46808
  quantity,
46779
46809
  dimension: "ROW",
46780
46810
  });
46781
- this.props.focusGrid();
46811
+ this.focusDefaultElement();
46782
46812
  // After adding new rows, scroll down to the new last row
46783
46813
  const { scrollX } = this.env.model.getters.getActiveSheetScrollInfo();
46784
46814
  const { end } = this.env.model.getters.getRowDimensions(activeSheetId, rowNumber + quantity - 1);
@@ -46791,7 +46821,12 @@ class GridAddRowsFooter extends Component {
46791
46821
  if (this.inputRef.el !== document.activeElement || ev.target === this.inputRef.el) {
46792
46822
  return;
46793
46823
  }
46794
- this.props.focusGrid();
46824
+ this.focusDefaultElement();
46825
+ }
46826
+ focusDefaultElement() {
46827
+ if (document.activeElement === this.inputRef.el) {
46828
+ this.DOMFocusableElementStore.focus();
46829
+ }
46795
46830
  }
46796
46831
  }
46797
46832
 
@@ -47066,7 +47101,6 @@ class GridOverlay extends Component {
47066
47101
  onCellClicked: { type: Function, optional: true },
47067
47102
  onCellRightClicked: { type: Function, optional: true },
47068
47103
  onGridResized: { type: Function, optional: true },
47069
- onFigureDeleted: { type: Function, optional: true },
47070
47104
  onGridMoved: Function,
47071
47105
  gridOverlayDimensions: String,
47072
47106
  slots: { type: Object, optional: true },
@@ -47081,7 +47115,6 @@ class GridOverlay extends Component {
47081
47115
  onCellClicked: () => { },
47082
47116
  onCellRightClicked: () => { },
47083
47117
  onGridResized: () => { },
47084
- onFigureDeleted: () => { },
47085
47118
  };
47086
47119
  gridOverlay = useRef("gridOverlay");
47087
47120
  cellPopovers;
@@ -51940,7 +51973,7 @@ function useHighlights(highlightProvider) {
51940
51973
  }
51941
51974
 
51942
51975
  css /* scss */ `
51943
- .o-cf-preview {
51976
+ .o-spreadsheet .o-cf-preview {
51944
51977
  &.o-cf-cursor-ptr {
51945
51978
  cursor: pointer;
51946
51979
  }
@@ -51948,6 +51981,7 @@ css /* scss */ `
51948
51981
  border-bottom: 1px solid ${GRAY_300};
51949
51982
  height: 80px;
51950
51983
  padding: 10px;
51984
+ box-sizing: border-box;
51951
51985
  position: relative;
51952
51986
  cursor: pointer;
51953
51987
  &:hover,
@@ -51961,7 +51995,6 @@ css /* scss */ `
51961
51995
  .o-cf-preview-icon {
51962
51996
  border: 1px solid ${GRAY_300};
51963
51997
  background-color: #fff;
51964
- position: absolute;
51965
51998
  height: 50px;
51966
51999
  width: 50px;
51967
52000
  .o-icon {
@@ -51970,12 +52003,6 @@ css /* scss */ `
51970
52003
  }
51971
52004
  }
51972
52005
  .o-cf-preview-description {
51973
- left: 65px;
51974
- margin-bottom: auto;
51975
- margin-right: 8px;
51976
- margin-top: auto;
51977
- position: relative;
51978
- width: 142px;
51979
52006
  .o-cf-preview-description-rule {
51980
52007
  margin-bottom: 4px;
51981
52008
  max-height: 2.8em;
@@ -51985,16 +52012,11 @@ css /* scss */ `
51985
52012
  font-size: 12px;
51986
52013
  }
51987
52014
  }
51988
- .o-cf-delete {
51989
- left: 90%;
51990
- top: 39%;
51991
- position: absolute;
51992
- }
51993
52015
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
51994
52016
  display: none !important;
51995
52017
  }
51996
52018
  .o-cf-drag-handle {
51997
- left: -8px;
52019
+ left: 2px;
51998
52020
  cursor: move;
51999
52021
  .o-icon {
52000
52022
  width: 6px;
@@ -56039,12 +56061,41 @@ const dateGranularities = [
56039
56061
  pivotRegistry.add("SPREADSHEET", {
56040
56062
  ui: SpreadsheetPivot,
56041
56063
  definition: SpreadsheetPivotRuntimeDefinition,
56042
- externalData: false,
56043
56064
  dateGranularities: [...dateGranularities],
56044
56065
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
56045
56066
  isMeasureCandidate: (field) => field.type !== "boolean",
56046
56067
  isGroupable: () => true,
56068
+ adaptRanges: (getters, definition, applyChange) => {
56069
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
56070
+ return definition;
56071
+ }
56072
+ const { sheetId, zone } = definition.dataSet;
56073
+ const range = getters.getRangeFromZone(sheetId, zone);
56074
+ const adaptedRange = adaptPivotRange(range, applyChange);
56075
+ if (adaptedRange === range) {
56076
+ return definition;
56077
+ }
56078
+ const dataSet = adaptedRange && {
56079
+ sheetId: adaptedRange.sheetId,
56080
+ zone: adaptedRange.zone,
56081
+ };
56082
+ return { ...definition, dataSet };
56083
+ },
56047
56084
  });
56085
+ function adaptPivotRange(range, applyChange) {
56086
+ if (!range) {
56087
+ return undefined;
56088
+ }
56089
+ const change = applyChange(range);
56090
+ switch (change.changeType) {
56091
+ case "NONE":
56092
+ return range;
56093
+ case "REMOVE":
56094
+ return undefined;
56095
+ default:
56096
+ return change.range;
56097
+ }
56098
+ }
56048
56099
 
56049
56100
  class PivotSidePanelStore extends SpreadsheetStore {
56050
56101
  pivotId;
@@ -62197,6 +62248,7 @@ function rangeToMerge(mergeId, range) {
62197
62248
  class RangeAdapter {
62198
62249
  getters;
62199
62250
  providers = [];
62251
+ isAdaptingRanges = false;
62200
62252
  constructor(getters) {
62201
62253
  this.getters = getters;
62202
62254
  }
@@ -62228,6 +62280,9 @@ class RangeAdapter {
62228
62280
  }
62229
62281
  beforeHandle(command) { }
62230
62282
  handle(cmd) {
62283
+ if (this.isAdaptingRanges) {
62284
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
62285
+ }
62231
62286
  const rangeAdapter = getRangeAdapter(cmd);
62232
62287
  if (rangeAdapter?.applyChange) {
62233
62288
  this.executeOnAllRanges(rangeAdapter.applyChange, rangeAdapter.sheetId, rangeAdapter.sheetName);
@@ -62250,10 +62305,12 @@ class RangeAdapter {
62250
62305
  };
62251
62306
  }
62252
62307
  executeOnAllRanges(adaptRange, sheetId, sheetName) {
62308
+ this.isAdaptingRanges = true;
62253
62309
  const func = this.verifyRangeRemoved(adaptRange);
62254
62310
  for (const provider of this.providers) {
62255
62311
  provider(func, sheetId, sheetName);
62256
62312
  }
62313
+ this.isAdaptingRanges = false;
62257
62314
  }
62258
62315
  /**
62259
62316
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -64289,6 +64346,18 @@ class PivotCorePlugin extends CorePlugin {
64289
64346
  }
64290
64347
  }
64291
64348
  adaptRanges(applyChange) {
64349
+ for (const pivotId in this.pivots) {
64350
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
64351
+ if (!definition) {
64352
+ continue;
64353
+ }
64354
+ const newDefinition = pivotRegistry
64355
+ .get(definition.type)
64356
+ ?.adaptRanges?.(this.getters, definition, applyChange);
64357
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
64358
+ this.history.update("pivots", pivotId, "definition", newDefinition);
64359
+ }
64360
+ }
64292
64361
  for (const sheetId in this.compiledMeasureFormulas) {
64293
64362
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
64294
64363
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -64540,20 +64609,6 @@ class SettingsPlugin extends CorePlugin {
64540
64609
  }
64541
64610
  }
64542
64611
 
64543
- function adaptPivotRange(range, applyChange) {
64544
- if (!range) {
64545
- return undefined;
64546
- }
64547
- const change = applyChange(range);
64548
- switch (change.changeType) {
64549
- case "NONE":
64550
- return range;
64551
- case "REMOVE":
64552
- return undefined;
64553
- default:
64554
- return change.range;
64555
- }
64556
- }
64557
64612
  class SpreadsheetPivotCorePlugin extends CorePlugin {
64558
64613
  allowDispatch(cmd) {
64559
64614
  switch (cmd.type) {
@@ -64564,24 +64619,6 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
64564
64619
  }
64565
64620
  return "Success" /* CommandResult.Success */;
64566
64621
  }
64567
- adaptRanges(applyChange) {
64568
- for (const pivotId of this.getters.getPivotIds()) {
64569
- const definition = this.getters.getPivotCoreDefinition(pivotId);
64570
- if (definition.type !== "SPREADSHEET") {
64571
- continue;
64572
- }
64573
- if (definition.dataSet) {
64574
- const { sheetId, zone } = definition.dataSet;
64575
- const range = this.getters.getRangeFromZone(sheetId, zone);
64576
- const adaptedRange = adaptPivotRange(range, applyChange);
64577
- const dataSet = adaptedRange && {
64578
- sheetId: adaptedRange.sheetId,
64579
- zone: adaptedRange.zone,
64580
- };
64581
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
64582
- }
64583
- }
64584
- }
64585
64622
  checkDataSetValidity(definition) {
64586
64623
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
64587
64624
  const { zone, sheetId } = definition.dataSet;
@@ -65923,6 +65960,9 @@ class Evaluator {
65923
65960
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
65924
65961
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
65925
65962
  }
65963
+ isArrayFormulaSpillBlocked(position) {
65964
+ return this.blockedArrayFormulas.has(position);
65965
+ }
65926
65966
  updateDependencies(position) {
65927
65967
  // removing dependencies is slow because it requires
65928
65968
  // to traverse the entire r-tree.
@@ -65934,13 +65974,8 @@ class Evaluator {
65934
65974
  addDependencies(position, dependencies) {
65935
65975
  this.formulaDependencies().addDependencies(position, dependencies);
65936
65976
  for (const range of dependencies) {
65937
- const sheetId = range.sheetId;
65938
- const { left, bottom, right, top } = range.zone;
65939
- for (let col = left; col <= right; col++) {
65940
- for (let row = top; row <= bottom; row++) {
65941
- this.computeAndSave({ sheetId, col, row });
65942
- }
65943
- }
65977
+ // ensure that all ranges are computed
65978
+ this.compilationParams.ensureRange(range);
65944
65979
  }
65945
65980
  }
65946
65981
  updateCompilationParameters() {
@@ -66143,6 +66178,10 @@ class Evaluator {
66143
66178
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
66144
66179
  const nbColumns = formulaReturn.length;
66145
66180
  const nbRows = formulaReturn[0].length;
66181
+ if (nbRows === 0) {
66182
+ // empty matrix
66183
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
66184
+ }
66146
66185
  const resultZone = {
66147
66186
  top: formulaPosition.row,
66148
66187
  bottom: formulaPosition.row + nbRows - 1,
@@ -66418,6 +66457,7 @@ class EvaluationPlugin extends CoreViewPlugin {
66418
66457
  "getEvaluatedCellsPositions",
66419
66458
  "getSpreadZone",
66420
66459
  "getArrayFormulaSpreadingOn",
66460
+ "isArrayFormulaSpillBlocked",
66421
66461
  "isEmpty",
66422
66462
  ];
66423
66463
  shouldRebuildDependenciesGraph = true;
@@ -66530,6 +66570,9 @@ class EvaluationPlugin extends CoreViewPlugin {
66530
66570
  getArrayFormulaSpreadingOn(position) {
66531
66571
  return this.evaluator.getArrayFormulaSpreadingOn(position);
66532
66572
  }
66573
+ isArrayFormulaSpillBlocked(position) {
66574
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
66575
+ }
66533
66576
  /**
66534
66577
  * Check if a zone only contains empty cells
66535
66578
  */
@@ -68579,9 +68622,7 @@ class PivotUIPlugin extends CoreViewPlugin {
68579
68622
  handle(cmd) {
68580
68623
  if (invalidateEvaluationCommands.has(cmd.type)) {
68581
68624
  for (const pivotId of this.getters.getPivotIds()) {
68582
- if (!pivotRegistry.get(this.getters.getPivotCoreDefinition(pivotId).type).externalData) {
68583
- this.setupPivot(pivotId, { recreate: true });
68584
- }
68625
+ this.setupPivot(pivotId, { recreate: true });
68585
68626
  }
68586
68627
  }
68587
68628
  switch (cmd.type) {
@@ -68789,7 +68830,7 @@ class PivotUIPlugin extends CoreViewPlugin {
68789
68830
  pivot.init({ reload: true });
68790
68831
  }
68791
68832
  setupPivot(pivotId, { recreate } = { recreate: false }) {
68792
- const definition = this.getters.getPivotCoreDefinition(pivotId);
68833
+ const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
68793
68834
  if (!(pivotId in this.pivots)) {
68794
68835
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
68795
68836
  this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
@@ -78042,16 +78083,18 @@ class ClickableCellsStore extends SpreadsheetStore {
78042
78083
  get clickableCells() {
78043
78084
  const cells = [];
78044
78085
  const getters = this.getters;
78045
- const sheetId = getters.getActiveSheetId();
78046
78086
  for (const position of this.getters.getVisibleCellPositions()) {
78047
78087
  const item = this.getClickableItem(position);
78048
78088
  if (!item) {
78049
78089
  continue;
78050
78090
  }
78051
78091
  const title = typeof item.title === "function" ? item.title(position, getters) : item.title;
78052
- const zone = getters.expandZone(sheetId, positionToZone(position));
78092
+ const rect = this.getClickableCellRect(position);
78093
+ if (!rect) {
78094
+ continue;
78095
+ }
78053
78096
  cells.push({
78054
- coordinates: getters.getVisibleRect(zone),
78097
+ coordinates: rect,
78055
78098
  position,
78056
78099
  action: item.execute,
78057
78100
  title: title || "",
@@ -78059,6 +78102,31 @@ class ClickableCellsStore extends SpreadsheetStore {
78059
78102
  }
78060
78103
  return cells;
78061
78104
  }
78105
+ getClickableCellRect(position) {
78106
+ const zone = this.getters.expandZone(position.sheetId, positionToZone(position));
78107
+ const clickableRect = this.getters.getVisibleRect(zone);
78108
+ const icons = this.getters.getCellIcons(position);
78109
+ const iconsAtPosition = {
78110
+ center: icons.find((icon) => icon.horizontalAlign === "center"),
78111
+ left: icons.find((icon) => icon.horizontalAlign === "left"),
78112
+ right: icons.find((icon) => icon.horizontalAlign === "right"),
78113
+ };
78114
+ if (iconsAtPosition.center?.onClick) {
78115
+ return undefined;
78116
+ }
78117
+ if (iconsAtPosition.right?.onClick) {
78118
+ const cellRect = this.getters.getRect(zone);
78119
+ const iconRect = this.getters.getCellIconRect(iconsAtPosition.right, cellRect);
78120
+ clickableRect.width -= iconRect.width + iconsAtPosition.right.margin;
78121
+ }
78122
+ if (iconsAtPosition.left?.onClick) {
78123
+ const cellRect = this.getters.getRect(zone);
78124
+ const iconRect = this.getters.getCellIconRect(iconsAtPosition.left, cellRect);
78125
+ clickableRect.x += iconRect.width + iconsAtPosition.left.margin;
78126
+ clickableRect.width -= iconRect.width + iconsAtPosition.left.margin;
78127
+ }
78128
+ return clickableRect;
78129
+ }
78062
78130
  }
78063
78131
 
78064
78132
  css /* scss */ `
@@ -78815,7 +78883,7 @@ class SmallBottomBar extends Component {
78815
78883
  height: this.focus === "inactive" ? "26px" : "fit-content",
78816
78884
  "max-height": `130px`,
78817
78885
  }),
78818
- showAssistant: !isIOS(), // Hide assistant on iOS as it breaks visually
78886
+ showAssistant: false, // Hide assistant in small composer as it gets cropped ATM
78819
78887
  placeholder: this.composerStore.placeholder,
78820
78888
  };
78821
78889
  }
@@ -80307,7 +80375,7 @@ class Spreadsheet extends Component {
80307
80375
  document.activeElement?.contains(this.spreadsheetRef.el)) {
80308
80376
  this.focusGrid();
80309
80377
  }
80310
- }, () => [this.env.model.getters.getActiveSheetId()]);
80378
+ });
80311
80379
  useExternalListener(window, "resize", () => this.render(true));
80312
80380
  // For some reason, the wheel event is not properly registered inside templates
80313
80381
  // in Chromium-based browsers based on chromium 125
@@ -84900,6 +84968,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
84900
84968
  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, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
84901
84969
 
84902
84970
 
84903
- __info__.version = "18.4.18";
84904
- __info__.date = "2025-11-24T07:42:07.821Z";
84905
- __info__.hash = "4f83667";
84971
+ __info__.version = "18.4.22";
84972
+ __info__.date = "2025-12-26T10:19:07.786Z";
84973
+ __info__.hash = "6ddac00";