@odoo/o-spreadsheet 16.4.34 → 16.4.37

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.
@@ -3236,8 +3236,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
3236
3236
  /**
3237
3237
  * Create a range from a xc. If the xc is empty, this function returns undefined.
3238
3238
  */
3239
- function createRange(getters, sheetId, range) {
3240
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
3239
+ function createValidRange(getters, sheetId, xc) {
3240
+ if (!xc)
3241
+ return;
3242
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
3243
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
3241
3244
  }
3242
3245
  /**
3243
3246
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5704,6 +5707,7 @@ const FilterMenuPopoverBuilder = {
5704
5707
  };
5705
5708
 
5706
5709
  const macRegex = /Mac/i;
5710
+ const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
5707
5711
  /**
5708
5712
  * Return true if the event was triggered from
5709
5713
  * a child element.
@@ -5742,6 +5746,31 @@ function* iterateChildren(el) {
5742
5746
  function getOpenedMenus() {
5743
5747
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
5744
5748
  }
5749
+ const letterRegex = /^[a-zA-Z]$/;
5750
+ /**
5751
+ * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
5752
+ *
5753
+ * @argument ev - The keyboard event to transform
5754
+ * @argument mode - Use either ev.key of ev.code to get the string shortcut
5755
+ *
5756
+ * @example
5757
+ * event : { ctrlKey: true, key: "a" } => "Ctrl+A"
5758
+ * event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
5759
+ */
5760
+ function keyboardEventToShortcutString(ev, mode = "key") {
5761
+ let keyDownString = "";
5762
+ if (!MODIFIER_KEYS.includes(ev.key)) {
5763
+ if (isCtrlKey(ev))
5764
+ keyDownString += "Ctrl+";
5765
+ if (ev.altKey)
5766
+ keyDownString += "Alt+";
5767
+ if (ev.shiftKey)
5768
+ keyDownString += "Shift+";
5769
+ }
5770
+ const key = mode === "key" ? ev.key : ev.code;
5771
+ keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
5772
+ return keyDownString;
5773
+ }
5745
5774
  function isMacOS() {
5746
5775
  return Boolean(macRegex.test(navigator.userAgent));
5747
5776
  }
@@ -5760,8 +5789,7 @@ function isCtrlKey(ev) {
5760
5789
  */
5761
5790
  function useSpreadsheetRect() {
5762
5791
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
5763
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
5764
- updatePosition();
5792
+ let spreadsheetElement = null;
5765
5793
  function updatePosition() {
5766
5794
  if (!spreadsheetElement) {
5767
5795
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -5899,7 +5927,7 @@ class Popover extends owl.Component {
5899
5927
  if (!anchor)
5900
5928
  return;
5901
5929
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
5902
- const elDims = {
5930
+ let elDims = {
5903
5931
  width: el.getBoundingClientRect().width,
5904
5932
  height: el.getBoundingClientRect().height,
5905
5933
  };
@@ -5907,7 +5935,14 @@ class Popover extends owl.Component {
5907
5935
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
5908
5936
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
5909
5937
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
5910
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
5938
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
5939
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
5940
+ // Re-compute the dimensions after setting the max-width and max-height
5941
+ elDims = {
5942
+ width: el.getBoundingClientRect().width,
5943
+ height: el.getBoundingClientRect().height,
5944
+ };
5945
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
5911
5946
  for (const property of Object.keys(style)) {
5912
5947
  el.style[property] = style[property];
5913
5948
  }
@@ -5983,8 +6018,6 @@ class PopoverPositionContext {
5983
6018
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
5984
6019
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
5985
6020
  const cssProperties = {
5986
- "max-height": maxHeight + "px",
5987
- "max-width": maxWidth + "px",
5988
6021
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
5989
6022
  this.spreadsheetOffset.y -
5990
6023
  verticalOffset +
@@ -16542,7 +16575,7 @@ class BarChart extends AbstractChart {
16542
16575
  constructor(definition, sheetId, getters) {
16543
16576
  super(definition, sheetId, getters);
16544
16577
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
16545
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
16578
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
16546
16579
  this.background = definition.background;
16547
16580
  this.verticalAxisPosition = definition.verticalAxisPosition;
16548
16581
  this.legendPosition = definition.legendPosition;
@@ -16787,7 +16820,7 @@ class GaugeChart extends AbstractChart {
16787
16820
  type = "gauge";
16788
16821
  constructor(definition, sheetId, getters) {
16789
16822
  super(definition, sheetId, getters);
16790
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
16823
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
16791
16824
  this.sectionRule = definition.sectionRule;
16792
16825
  this.background = definition.background;
16793
16826
  }
@@ -17126,7 +17159,7 @@ class LineChart extends AbstractChart {
17126
17159
  constructor(definition, sheetId, getters) {
17127
17160
  super(definition, sheetId, getters);
17128
17161
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17129
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
17162
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
17130
17163
  this.background = definition.background;
17131
17164
  this.verticalAxisPosition = definition.verticalAxisPosition;
17132
17165
  this.legendPosition = definition.legendPosition;
@@ -17424,7 +17457,7 @@ class PieChart extends AbstractChart {
17424
17457
  constructor(definition, sheetId, getters) {
17425
17458
  super(definition, sheetId, getters);
17426
17459
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17427
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
17460
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
17428
17461
  this.background = definition.background;
17429
17462
  this.legendPosition = definition.legendPosition;
17430
17463
  this.aggregated = definition.aggregated;
@@ -17592,8 +17625,8 @@ class ScorecardChart extends AbstractChart {
17592
17625
  type = "scorecard";
17593
17626
  constructor(definition, sheetId, getters) {
17594
17627
  super(definition, sheetId, getters);
17595
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
17596
- this.baseline = createRange(getters, sheetId, definition.baseline);
17628
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
17629
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
17597
17630
  this.baselineMode = definition.baselineMode;
17598
17631
  this.baselineDescr = definition.baselineDescr;
17599
17632
  this.background = definition.background;
@@ -20952,7 +20985,7 @@ class LineBarPieConfigPanel extends owl.Component {
20952
20985
  }
20953
20986
  const getters = this.env.model.getters;
20954
20987
  const sheetId = getters.getActiveSheetId();
20955
- const labelRange = createRange(getters, sheetId, this.labelRange);
20988
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
20956
20989
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
20957
20990
  if (dataSets.length) {
20958
20991
  return dataSets[0].dataRange.zone.top + 1;
@@ -23417,14 +23450,14 @@ class FigureComponent extends owl.Component {
23417
23450
  }
23418
23451
  onKeyDown(ev) {
23419
23452
  const figure = this.props.figure;
23420
- switch (ev.key) {
23453
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
23454
+ switch (keyDownShortcut) {
23421
23455
  case "Delete":
23422
23456
  this.env.model.dispatch("DELETE_FIGURE", {
23423
23457
  sheetId: this.env.model.getters.getActiveSheetId(),
23424
23458
  id: figure.id,
23425
23459
  });
23426
23460
  this.props.onFigureDeleted();
23427
- ev.stopPropagation();
23428
23461
  ev.preventDefault();
23429
23462
  ev.stopPropagation();
23430
23463
  break;
@@ -23445,7 +23478,22 @@ class FigureComponent extends owl.Component {
23445
23478
  x: figure.x + delta[0],
23446
23479
  y: figure.y + delta[1],
23447
23480
  });
23481
+ ev.preventDefault();
23448
23482
  ev.stopPropagation();
23483
+ break;
23484
+ case "Ctrl+A":
23485
+ // Maybe in the future we will implement a way to select all figures
23486
+ ev.preventDefault();
23487
+ ev.stopPropagation();
23488
+ break;
23489
+ case "Ctrl+Y":
23490
+ case "Ctrl+Z":
23491
+ if (keyDownShortcut === "Ctrl+Y") {
23492
+ this.env.model.dispatch("REQUEST_REDO");
23493
+ }
23494
+ else if (keyDownShortcut === "Ctrl+Z") {
23495
+ this.env.model.dispatch("REQUEST_UNDO");
23496
+ }
23449
23497
  ev.preventDefault();
23450
23498
  ev.stopPropagation();
23451
23499
  break;
@@ -24316,8 +24364,15 @@ class Composer extends owl.Component {
24316
24364
  }
24317
24365
  onPaste(ev) {
24318
24366
  if (this.env.model.getters.getEditionMode() !== "inactive") {
24367
+ // let the browser clipboard work
24319
24368
  ev.stopPropagation();
24320
24369
  }
24370
+ else {
24371
+ // the user meant to paste in the sheet, not open the composer with the pasted content
24372
+ // While we're not editing, we still have the focus and should therefore prevent
24373
+ // the native "paste" to occur.
24374
+ ev.preventDefault();
24375
+ }
24321
24376
  }
24322
24377
  /*
24323
24378
  * Triggered automatically by the content-editable between the keydown and key up
@@ -24326,10 +24381,6 @@ class Composer extends owl.Component {
24326
24381
  if (!this.shouldProcessInputEvents) {
24327
24382
  return;
24328
24383
  }
24329
- if (ev.inputType === "insertFromPaste" &&
24330
- this.env.model.getters.getEditionMode() === "inactive") {
24331
- return;
24332
- }
24333
24384
  ev.stopPropagation();
24334
24385
  let content;
24335
24386
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -24760,10 +24811,7 @@ class GridComposer extends owl.Component {
24760
24811
  }
24761
24812
  get containerStyle() {
24762
24813
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
24763
- return `
24764
- position: absolute;
24765
- z-index: -1000;
24766
- `;
24814
+ return `z-index: -1000;`;
24767
24815
  }
24768
24816
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
24769
24817
  const cell = this.env.model.getters.getActiveCell();
@@ -25346,7 +25394,7 @@ class FiguresContainer extends owl.Component {
25346
25394
  });
25347
25395
  }
25348
25396
  getContainerRect(container) {
25349
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
25397
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
25350
25398
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
25351
25399
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
25352
25400
  const width = viewWidth - x;
@@ -34593,6 +34641,9 @@ class RangeAdapter {
34593
34641
  if (range.invalidXc) {
34594
34642
  return range.invalidXc;
34595
34643
  }
34644
+ if (!this.getters.tryGetSheet(range.sheetId)) {
34645
+ return INCORRECT_RANGE_STRING;
34646
+ }
34596
34647
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
34597
34648
  return INCORRECT_RANGE_STRING;
34598
34649
  }
@@ -37644,16 +37695,22 @@ class EvaluationPlugin extends UIPlugin {
37644
37695
  let newContent = undefined;
37645
37696
  let newFormat = undefined;
37646
37697
  let isExported = true;
37698
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37647
37699
  const formulaCell = this.getCorrespondingFormulaCell(position);
37648
37700
  if (formulaCell) {
37649
37701
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
37650
37702
  isFormula = isExported;
37651
37703
  if (!isExported) {
37652
- newContent = value.toString();
37653
- newFormat = evaluatedCell.format;
37704
+ // If the cell contains a non-exported formula and that is evaluates to
37705
+ // nothing* ,we don't export it.
37706
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
37707
+ // the empty string.
37708
+ if (value !== "") {
37709
+ newContent = value.toString();
37710
+ newFormat = evaluatedCell.format;
37711
+ }
37654
37712
  }
37655
37713
  }
37656
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37657
37714
  const exportedCellData = exportedSheetData.cells[xc] || {};
37658
37715
  const format = newFormat
37659
37716
  ? getItemId(newFormat, data.formats)
@@ -46524,9 +46581,11 @@ class BottomBarSheet extends owl.Component {
46524
46581
  if (ev.key === "Enter") {
46525
46582
  ev.preventDefault();
46526
46583
  this.stopEdition();
46584
+ this.env.focusableElement.focus();
46527
46585
  }
46528
46586
  if (ev.key === "Escape") {
46529
46587
  this.cancelEdition();
46588
+ this.env.focusableElement.focus();
46530
46589
  }
46531
46590
  }
46532
46591
  onClickSheetName(ev) {
@@ -51142,7 +51201,11 @@ function addRows(construct, data, sheet) {
51142
51201
  let cellNode = escapeXml ``;
51143
51202
  // Either formula or static value inside the cell
51144
51203
  if (cell.isFormula) {
51145
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
51204
+ const res = addFormula(cell);
51205
+ if (!res) {
51206
+ continue;
51207
+ }
51208
+ ({ attrs: additionalAttrs, node: cellNode } = res);
51146
51209
  }
51147
51210
  else if (cell.content && isMarkdownLink(cell.content)) {
51148
51211
  const { label } = parseMarkdownLink(cell.content);
@@ -52070,6 +52133,7 @@ const helpers = {
52070
52133
  isDefined: isDefined$1,
52071
52134
  lazy,
52072
52135
  genericRepeat,
52136
+ deepEquals,
52073
52137
  };
52074
52138
  const links = {
52075
52139
  isMarkdownLink,
@@ -52137,6 +52201,6 @@ exports.setTranslationMethod = setTranslationMethod;
52137
52201
  exports.tokenize = tokenize;
52138
52202
 
52139
52203
 
52140
- __info__.version = '16.4.34';
52141
- __info__.date = '2024-05-24T11:27:29.421Z';
52142
- __info__.hash = '5e74805';
52204
+ __info__.version = '16.4.37';
52205
+ __info__.date = '2024-06-14T10:00:27.521Z';
52206
+ __info__.hash = '195b41b';
@@ -967,6 +967,10 @@ declare function isDefined<T>(argument: T | undefined): argument is T;
967
967
  * Lazy value computed by the provided function.
968
968
  */
969
969
  declare function lazy<T>(fn: (() => T) | T): Lazy<T>;
970
+ /**
971
+ * Compares two objects.
972
+ */
973
+ declare function deepEquals(o1: any, o2: any): boolean;
970
974
 
971
975
  interface ConstructorArgs {
972
976
  readonly zone: Readonly<Zone | UnboundedZone>;
@@ -7363,6 +7367,7 @@ declare const helpers: {
7363
7367
  isDefined: typeof isDefined;
7364
7368
  lazy: typeof lazy;
7365
7369
  genericRepeat: typeof genericRepeat;
7370
+ deepEquals: typeof deepEquals;
7366
7371
  };
7367
7372
  declare const links: {
7368
7373
  isMarkdownLink: typeof isMarkdownLink;
@@ -3232,8 +3232,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
3232
3232
  /**
3233
3233
  * Create a range from a xc. If the xc is empty, this function returns undefined.
3234
3234
  */
3235
- function createRange(getters, sheetId, range) {
3236
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
3235
+ function createValidRange(getters, sheetId, xc) {
3236
+ if (!xc)
3237
+ return;
3238
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
3239
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
3237
3240
  }
3238
3241
  /**
3239
3242
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5700,6 +5703,7 @@ const FilterMenuPopoverBuilder = {
5700
5703
  };
5701
5704
 
5702
5705
  const macRegex = /Mac/i;
5706
+ const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
5703
5707
  /**
5704
5708
  * Return true if the event was triggered from
5705
5709
  * a child element.
@@ -5738,6 +5742,31 @@ function* iterateChildren(el) {
5738
5742
  function getOpenedMenus() {
5739
5743
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
5740
5744
  }
5745
+ const letterRegex = /^[a-zA-Z]$/;
5746
+ /**
5747
+ * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
5748
+ *
5749
+ * @argument ev - The keyboard event to transform
5750
+ * @argument mode - Use either ev.key of ev.code to get the string shortcut
5751
+ *
5752
+ * @example
5753
+ * event : { ctrlKey: true, key: "a" } => "Ctrl+A"
5754
+ * event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
5755
+ */
5756
+ function keyboardEventToShortcutString(ev, mode = "key") {
5757
+ let keyDownString = "";
5758
+ if (!MODIFIER_KEYS.includes(ev.key)) {
5759
+ if (isCtrlKey(ev))
5760
+ keyDownString += "Ctrl+";
5761
+ if (ev.altKey)
5762
+ keyDownString += "Alt+";
5763
+ if (ev.shiftKey)
5764
+ keyDownString += "Shift+";
5765
+ }
5766
+ const key = mode === "key" ? ev.key : ev.code;
5767
+ keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
5768
+ return keyDownString;
5769
+ }
5741
5770
  function isMacOS() {
5742
5771
  return Boolean(macRegex.test(navigator.userAgent));
5743
5772
  }
@@ -5756,8 +5785,7 @@ function isCtrlKey(ev) {
5756
5785
  */
5757
5786
  function useSpreadsheetRect() {
5758
5787
  const position = useState({ x: 0, y: 0, width: 0, height: 0 });
5759
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
5760
- updatePosition();
5788
+ let spreadsheetElement = null;
5761
5789
  function updatePosition() {
5762
5790
  if (!spreadsheetElement) {
5763
5791
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -5895,7 +5923,7 @@ class Popover extends Component {
5895
5923
  if (!anchor)
5896
5924
  return;
5897
5925
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
5898
- const elDims = {
5926
+ let elDims = {
5899
5927
  width: el.getBoundingClientRect().width,
5900
5928
  height: el.getBoundingClientRect().height,
5901
5929
  };
@@ -5903,7 +5931,14 @@ class Popover extends Component {
5903
5931
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
5904
5932
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
5905
5933
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
5906
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
5934
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
5935
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
5936
+ // Re-compute the dimensions after setting the max-width and max-height
5937
+ elDims = {
5938
+ width: el.getBoundingClientRect().width,
5939
+ height: el.getBoundingClientRect().height,
5940
+ };
5941
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
5907
5942
  for (const property of Object.keys(style)) {
5908
5943
  el.style[property] = style[property];
5909
5944
  }
@@ -5979,8 +6014,6 @@ class PopoverPositionContext {
5979
6014
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
5980
6015
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
5981
6016
  const cssProperties = {
5982
- "max-height": maxHeight + "px",
5983
- "max-width": maxWidth + "px",
5984
6017
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
5985
6018
  this.spreadsheetOffset.y -
5986
6019
  verticalOffset +
@@ -16538,7 +16571,7 @@ class BarChart extends AbstractChart {
16538
16571
  constructor(definition, sheetId, getters) {
16539
16572
  super(definition, sheetId, getters);
16540
16573
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
16541
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
16574
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
16542
16575
  this.background = definition.background;
16543
16576
  this.verticalAxisPosition = definition.verticalAxisPosition;
16544
16577
  this.legendPosition = definition.legendPosition;
@@ -16783,7 +16816,7 @@ class GaugeChart extends AbstractChart {
16783
16816
  type = "gauge";
16784
16817
  constructor(definition, sheetId, getters) {
16785
16818
  super(definition, sheetId, getters);
16786
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
16819
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
16787
16820
  this.sectionRule = definition.sectionRule;
16788
16821
  this.background = definition.background;
16789
16822
  }
@@ -17122,7 +17155,7 @@ class LineChart extends AbstractChart {
17122
17155
  constructor(definition, sheetId, getters) {
17123
17156
  super(definition, sheetId, getters);
17124
17157
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17125
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
17158
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
17126
17159
  this.background = definition.background;
17127
17160
  this.verticalAxisPosition = definition.verticalAxisPosition;
17128
17161
  this.legendPosition = definition.legendPosition;
@@ -17420,7 +17453,7 @@ class PieChart extends AbstractChart {
17420
17453
  constructor(definition, sheetId, getters) {
17421
17454
  super(definition, sheetId, getters);
17422
17455
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17423
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
17456
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
17424
17457
  this.background = definition.background;
17425
17458
  this.legendPosition = definition.legendPosition;
17426
17459
  this.aggregated = definition.aggregated;
@@ -17588,8 +17621,8 @@ class ScorecardChart extends AbstractChart {
17588
17621
  type = "scorecard";
17589
17622
  constructor(definition, sheetId, getters) {
17590
17623
  super(definition, sheetId, getters);
17591
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
17592
- this.baseline = createRange(getters, sheetId, definition.baseline);
17624
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
17625
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
17593
17626
  this.baselineMode = definition.baselineMode;
17594
17627
  this.baselineDescr = definition.baselineDescr;
17595
17628
  this.background = definition.background;
@@ -20948,7 +20981,7 @@ class LineBarPieConfigPanel extends Component {
20948
20981
  }
20949
20982
  const getters = this.env.model.getters;
20950
20983
  const sheetId = getters.getActiveSheetId();
20951
- const labelRange = createRange(getters, sheetId, this.labelRange);
20984
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
20952
20985
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
20953
20986
  if (dataSets.length) {
20954
20987
  return dataSets[0].dataRange.zone.top + 1;
@@ -23413,14 +23446,14 @@ class FigureComponent extends Component {
23413
23446
  }
23414
23447
  onKeyDown(ev) {
23415
23448
  const figure = this.props.figure;
23416
- switch (ev.key) {
23449
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
23450
+ switch (keyDownShortcut) {
23417
23451
  case "Delete":
23418
23452
  this.env.model.dispatch("DELETE_FIGURE", {
23419
23453
  sheetId: this.env.model.getters.getActiveSheetId(),
23420
23454
  id: figure.id,
23421
23455
  });
23422
23456
  this.props.onFigureDeleted();
23423
- ev.stopPropagation();
23424
23457
  ev.preventDefault();
23425
23458
  ev.stopPropagation();
23426
23459
  break;
@@ -23441,7 +23474,22 @@ class FigureComponent extends Component {
23441
23474
  x: figure.x + delta[0],
23442
23475
  y: figure.y + delta[1],
23443
23476
  });
23477
+ ev.preventDefault();
23444
23478
  ev.stopPropagation();
23479
+ break;
23480
+ case "Ctrl+A":
23481
+ // Maybe in the future we will implement a way to select all figures
23482
+ ev.preventDefault();
23483
+ ev.stopPropagation();
23484
+ break;
23485
+ case "Ctrl+Y":
23486
+ case "Ctrl+Z":
23487
+ if (keyDownShortcut === "Ctrl+Y") {
23488
+ this.env.model.dispatch("REQUEST_REDO");
23489
+ }
23490
+ else if (keyDownShortcut === "Ctrl+Z") {
23491
+ this.env.model.dispatch("REQUEST_UNDO");
23492
+ }
23445
23493
  ev.preventDefault();
23446
23494
  ev.stopPropagation();
23447
23495
  break;
@@ -24312,8 +24360,15 @@ class Composer extends Component {
24312
24360
  }
24313
24361
  onPaste(ev) {
24314
24362
  if (this.env.model.getters.getEditionMode() !== "inactive") {
24363
+ // let the browser clipboard work
24315
24364
  ev.stopPropagation();
24316
24365
  }
24366
+ else {
24367
+ // the user meant to paste in the sheet, not open the composer with the pasted content
24368
+ // While we're not editing, we still have the focus and should therefore prevent
24369
+ // the native "paste" to occur.
24370
+ ev.preventDefault();
24371
+ }
24317
24372
  }
24318
24373
  /*
24319
24374
  * Triggered automatically by the content-editable between the keydown and key up
@@ -24322,10 +24377,6 @@ class Composer extends Component {
24322
24377
  if (!this.shouldProcessInputEvents) {
24323
24378
  return;
24324
24379
  }
24325
- if (ev.inputType === "insertFromPaste" &&
24326
- this.env.model.getters.getEditionMode() === "inactive") {
24327
- return;
24328
- }
24329
24380
  ev.stopPropagation();
24330
24381
  let content;
24331
24382
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -24756,10 +24807,7 @@ class GridComposer extends Component {
24756
24807
  }
24757
24808
  get containerStyle() {
24758
24809
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
24759
- return `
24760
- position: absolute;
24761
- z-index: -1000;
24762
- `;
24810
+ return `z-index: -1000;`;
24763
24811
  }
24764
24812
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
24765
24813
  const cell = this.env.model.getters.getActiveCell();
@@ -25342,7 +25390,7 @@ class FiguresContainer extends Component {
25342
25390
  });
25343
25391
  }
25344
25392
  getContainerRect(container) {
25345
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
25393
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
25346
25394
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
25347
25395
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
25348
25396
  const width = viewWidth - x;
@@ -34589,6 +34637,9 @@ class RangeAdapter {
34589
34637
  if (range.invalidXc) {
34590
34638
  return range.invalidXc;
34591
34639
  }
34640
+ if (!this.getters.tryGetSheet(range.sheetId)) {
34641
+ return INCORRECT_RANGE_STRING;
34642
+ }
34592
34643
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
34593
34644
  return INCORRECT_RANGE_STRING;
34594
34645
  }
@@ -37640,16 +37691,22 @@ class EvaluationPlugin extends UIPlugin {
37640
37691
  let newContent = undefined;
37641
37692
  let newFormat = undefined;
37642
37693
  let isExported = true;
37694
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37643
37695
  const formulaCell = this.getCorrespondingFormulaCell(position);
37644
37696
  if (formulaCell) {
37645
37697
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
37646
37698
  isFormula = isExported;
37647
37699
  if (!isExported) {
37648
- newContent = value.toString();
37649
- newFormat = evaluatedCell.format;
37700
+ // If the cell contains a non-exported formula and that is evaluates to
37701
+ // nothing* ,we don't export it.
37702
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
37703
+ // the empty string.
37704
+ if (value !== "") {
37705
+ newContent = value.toString();
37706
+ newFormat = evaluatedCell.format;
37707
+ }
37650
37708
  }
37651
37709
  }
37652
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37653
37710
  const exportedCellData = exportedSheetData.cells[xc] || {};
37654
37711
  const format = newFormat
37655
37712
  ? getItemId(newFormat, data.formats)
@@ -46520,9 +46577,11 @@ class BottomBarSheet extends Component {
46520
46577
  if (ev.key === "Enter") {
46521
46578
  ev.preventDefault();
46522
46579
  this.stopEdition();
46580
+ this.env.focusableElement.focus();
46523
46581
  }
46524
46582
  if (ev.key === "Escape") {
46525
46583
  this.cancelEdition();
46584
+ this.env.focusableElement.focus();
46526
46585
  }
46527
46586
  }
46528
46587
  onClickSheetName(ev) {
@@ -51138,7 +51197,11 @@ function addRows(construct, data, sheet) {
51138
51197
  let cellNode = escapeXml ``;
51139
51198
  // Either formula or static value inside the cell
51140
51199
  if (cell.isFormula) {
51141
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
51200
+ const res = addFormula(cell);
51201
+ if (!res) {
51202
+ continue;
51203
+ }
51204
+ ({ attrs: additionalAttrs, node: cellNode } = res);
51142
51205
  }
51143
51206
  else if (cell.content && isMarkdownLink(cell.content)) {
51144
51207
  const { label } = parseMarkdownLink(cell.content);
@@ -52066,6 +52129,7 @@ const helpers = {
52066
52129
  isDefined: isDefined$1,
52067
52130
  lazy,
52068
52131
  genericRepeat,
52132
+ deepEquals,
52069
52133
  };
52070
52134
  const links = {
52071
52135
  isMarkdownLink,
@@ -52101,6 +52165,6 @@ const constants = {
52101
52165
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
52102
52166
 
52103
52167
 
52104
- __info__.version = '16.4.34';
52105
- __info__.date = '2024-05-24T11:27:29.421Z';
52106
- __info__.hash = '5e74805';
52168
+ __info__.version = '16.4.37';
52169
+ __info__.date = '2024-06-14T10:00:27.521Z';
52170
+ __info__.hash = '195b41b';