@odoo/o-spreadsheet 17.0.23 → 17.0.25

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 17.0.23
6
- * @date 2024-05-24T11:27:27.416Z
7
- * @hash 6c10fec
5
+ * @version 17.0.25
6
+ * @date 2024-06-10T09:33:40.022Z
7
+ * @hash 1f01394
8
8
  */
9
9
 
10
10
  'use strict';
@@ -394,7 +394,10 @@ function deepCopy(obj) {
394
394
  * Check if the object is a plain old javascript object.
395
395
  */
396
396
  function isPlainObject(obj) {
397
- return typeof obj === "object" && obj?.constructor === Object;
397
+ return (typeof obj === "object" &&
398
+ obj !== null &&
399
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
400
+ (obj?.constructor === Object || obj?.constructor === undefined));
398
401
  }
399
402
  /**
400
403
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -4306,8 +4309,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
4306
4309
  /**
4307
4310
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4308
4311
  */
4309
- function createRange(getters, sheetId, range) {
4310
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4312
+ function createValidRange(getters, sheetId, xc) {
4313
+ if (!xc)
4314
+ return;
4315
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4316
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4311
4317
  }
4312
4318
  /**
4313
4319
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5235,8 +5241,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
5235
5241
  type = "scorecard";
5236
5242
  constructor(definition, sheetId, getters) {
5237
5243
  super(definition, sheetId, getters);
5238
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
5239
- this.baseline = createRange(getters, sheetId, definition.baseline);
5244
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
5245
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
5240
5246
  this.baselineMode = definition.baselineMode;
5241
5247
  this.baselineDescr = definition.baselineDescr;
5242
5248
  this.background = definition.background;
@@ -6707,6 +6713,7 @@ const FilterMenuPopoverBuilder = {
6707
6713
  };
6708
6714
 
6709
6715
  const macRegex = /Mac/i;
6716
+ const MODIFIER_KEYS$1 = ["Shift", "Control", "Alt", "Meta"];
6710
6717
  /**
6711
6718
  * Return true if the event was triggered from
6712
6719
  * a child element.
@@ -6745,6 +6752,31 @@ function* iterateChildren(el) {
6745
6752
  function getOpenedMenus() {
6746
6753
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
6747
6754
  }
6755
+ const letterRegex = /^[a-zA-Z]$/;
6756
+ /**
6757
+ * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
6758
+ *
6759
+ * @argument ev - The keyboard event to transform
6760
+ * @argument mode - Use either ev.key of ev.code to get the string shortcut
6761
+ *
6762
+ * @example
6763
+ * event : { ctrlKey: true, key: "a" } => "Ctrl+A"
6764
+ * event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
6765
+ */
6766
+ function keyboardEventToShortcutString(ev, mode = "key") {
6767
+ let keyDownString = "";
6768
+ if (!MODIFIER_KEYS$1.includes(ev.key)) {
6769
+ if (isCtrlKey(ev))
6770
+ keyDownString += "Ctrl+";
6771
+ if (ev.altKey)
6772
+ keyDownString += "Alt+";
6773
+ if (ev.shiftKey)
6774
+ keyDownString += "Shift+";
6775
+ }
6776
+ const key = mode === "key" ? ev.key : ev.code;
6777
+ keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
6778
+ return keyDownString;
6779
+ }
6748
6780
  function isMacOS() {
6749
6781
  return Boolean(macRegex.test(navigator.userAgent));
6750
6782
  }
@@ -6763,8 +6795,7 @@ function isCtrlKey(ev) {
6763
6795
  */
6764
6796
  function useSpreadsheetRect() {
6765
6797
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
6766
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
6767
- updatePosition();
6798
+ let spreadsheetElement = null;
6768
6799
  function updatePosition() {
6769
6800
  if (!spreadsheetElement) {
6770
6801
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -8537,7 +8568,7 @@ function chartToImage(runtime, figure, type) {
8537
8568
  if ("chartJsConfig" in runtime) {
8538
8569
  runtime.chartJsConfig.plugins = [backgroundColorChartJSPlugin];
8539
8570
  // @ts-ignore
8540
- const chart = new window.Chart(canvas, runtime.chartJsConfig);
8571
+ const chart = new window.Chart(canvas, deepCopy(runtime.chartJsConfig));
8541
8572
  const imgContent = chart.toBase64Image();
8542
8573
  chart.destroy();
8543
8574
  div.remove();
@@ -8581,7 +8612,7 @@ class BarChart extends AbstractChart {
8581
8612
  constructor(definition, sheetId, getters) {
8582
8613
  super(definition, sheetId, getters);
8583
8614
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
8584
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
8615
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
8585
8616
  this.background = definition.background;
8586
8617
  this.verticalAxisPosition = definition.verticalAxisPosition;
8587
8618
  this.legendPosition = definition.legendPosition;
@@ -8824,7 +8855,7 @@ class GaugeChart extends AbstractChart {
8824
8855
  type = "gauge";
8825
8856
  constructor(definition, sheetId, getters) {
8826
8857
  super(definition, sheetId, getters);
8827
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
8858
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
8828
8859
  this.sectionRule = definition.sectionRule;
8829
8860
  this.background = definition.background;
8830
8861
  }
@@ -9158,7 +9189,7 @@ class LineChart extends AbstractChart {
9158
9189
  constructor(definition, sheetId, getters) {
9159
9190
  super(definition, sheetId, getters);
9160
9191
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9161
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
9192
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
9162
9193
  this.background = definition.background;
9163
9194
  this.verticalAxisPosition = definition.verticalAxisPosition;
9164
9195
  this.legendPosition = definition.legendPosition;
@@ -9478,7 +9509,7 @@ class PieChart extends AbstractChart {
9478
9509
  constructor(definition, sheetId, getters) {
9479
9510
  super(definition, sheetId, getters);
9480
9511
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9481
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
9512
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
9482
9513
  this.background = definition.background;
9483
9514
  this.legendPosition = definition.legendPosition;
9484
9515
  this.aggregated = definition.aggregated;
@@ -21725,7 +21756,7 @@ class LineBarPieConfigPanel extends owl.Component {
21725
21756
  }
21726
21757
  const getters = this.env.model.getters;
21727
21758
  const sheetId = getters.getActiveSheetId();
21728
- const labelRange = createRange(getters, sheetId, this.labelRange);
21759
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
21729
21760
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
21730
21761
  if (dataSets.length) {
21731
21762
  return dataSets[0].dataRange.zone.top + 1;
@@ -25767,14 +25798,14 @@ class FigureComponent extends owl.Component {
25767
25798
  }
25768
25799
  onKeyDown(ev) {
25769
25800
  const figure = this.props.figure;
25770
- switch (ev.key) {
25801
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
25802
+ switch (keyDownShortcut) {
25771
25803
  case "Delete":
25772
25804
  this.env.model.dispatch("DELETE_FIGURE", {
25773
25805
  sheetId: this.env.model.getters.getActiveSheetId(),
25774
25806
  id: figure.id,
25775
25807
  });
25776
25808
  this.props.onFigureDeleted();
25777
- ev.stopPropagation();
25778
25809
  ev.preventDefault();
25779
25810
  ev.stopPropagation();
25780
25811
  break;
@@ -25795,7 +25826,22 @@ class FigureComponent extends owl.Component {
25795
25826
  x: figure.x + delta[0],
25796
25827
  y: figure.y + delta[1],
25797
25828
  });
25829
+ ev.preventDefault();
25830
+ ev.stopPropagation();
25831
+ break;
25832
+ case "Ctrl+A":
25833
+ // Maybe in the future we will implement a way to select all figures
25834
+ ev.preventDefault();
25798
25835
  ev.stopPropagation();
25836
+ break;
25837
+ case "Ctrl+Y":
25838
+ case "Ctrl+Z":
25839
+ if (keyDownShortcut === "Ctrl+Y") {
25840
+ this.env.model.dispatch("REQUEST_REDO");
25841
+ }
25842
+ else if (keyDownShortcut === "Ctrl+Z") {
25843
+ this.env.model.dispatch("REQUEST_UNDO");
25844
+ }
25799
25845
  ev.preventDefault();
25800
25846
  ev.stopPropagation();
25801
25847
  break;
@@ -26815,8 +26861,15 @@ class Composer extends owl.Component {
26815
26861
  }
26816
26862
  onPaste(ev) {
26817
26863
  if (this.env.model.getters.getEditionMode() !== "inactive") {
26864
+ // let the browser clipboard work
26818
26865
  ev.stopPropagation();
26819
26866
  }
26867
+ else {
26868
+ // the user meant to paste in the sheet, not open the composer with the pasted content
26869
+ // While we're not editing, we still have the focus and should therefore prevent
26870
+ // the native "paste" to occur.
26871
+ ev.preventDefault();
26872
+ }
26820
26873
  }
26821
26874
  /*
26822
26875
  * Triggered automatically by the content-editable between the keydown and key up
@@ -26825,10 +26878,6 @@ class Composer extends owl.Component {
26825
26878
  if (!this.shouldProcessInputEvents) {
26826
26879
  return;
26827
26880
  }
26828
- if (ev.inputType === "insertFromPaste" &&
26829
- this.env.model.getters.getEditionMode() === "inactive") {
26830
- return;
26831
- }
26832
26881
  ev.stopPropagation();
26833
26882
  let content;
26834
26883
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -27276,10 +27325,7 @@ class GridComposer extends owl.Component {
27276
27325
  }
27277
27326
  get containerStyle() {
27278
27327
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27279
- return `
27280
- position: absolute;
27281
- z-index: -1000;
27282
- `;
27328
+ return `z-index: -1000;`;
27283
27329
  }
27284
27330
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27285
27331
  const cell = this.env.model.getters.getActiveCell();
@@ -38572,6 +38618,9 @@ class RangeAdapter {
38572
38618
  if (range.invalidXc) {
38573
38619
  return range.invalidXc;
38574
38620
  }
38621
+ if (!this.getters.tryGetSheet(range.sheetId)) {
38622
+ return INCORRECT_RANGE_STRING;
38623
+ }
38575
38624
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
38576
38625
  return INCORRECT_RANGE_STRING;
38577
38626
  }
@@ -42023,16 +42072,22 @@ class EvaluationPlugin extends UIPlugin {
42023
42072
  let newContent = undefined;
42024
42073
  let newFormat = undefined;
42025
42074
  let isExported = true;
42075
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42026
42076
  const formulaCell = this.getCorrespondingFormulaCell(position);
42027
42077
  if (formulaCell) {
42028
42078
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
42029
42079
  isFormula = isExported;
42030
42080
  if (!isExported) {
42031
- newContent = value.toString();
42032
- newFormat = evaluatedCell.format;
42081
+ // If the cell contains a non-exported formula and that is evaluates to
42082
+ // nothing* ,we don't export it.
42083
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
42084
+ // the empty string.
42085
+ if (value !== "") {
42086
+ newContent = value.toString();
42087
+ newFormat = evaluatedCell.format;
42088
+ }
42033
42089
  }
42034
42090
  }
42035
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42036
42091
  const exportedCellData = exportedSheetData.cells[xc] || {};
42037
42092
  const format = newFormat
42038
42093
  ? getItemId(newFormat, data.formats)
@@ -51644,9 +51699,11 @@ class BottomBarSheet extends owl.Component {
51644
51699
  if (ev.key === "Enter") {
51645
51700
  ev.preventDefault();
51646
51701
  this.stopEdition();
51702
+ this.env.focusableElement.focus();
51647
51703
  }
51648
51704
  if (ev.key === "Escape") {
51649
51705
  this.cancelEdition();
51706
+ this.env.focusableElement.focus();
51650
51707
  }
51651
51708
  }
51652
51709
  onClickSheetName(ev) {
@@ -56395,7 +56452,11 @@ function addRows(construct, data, sheet) {
56395
56452
  let cellNode = escapeXml ``;
56396
56453
  // Either formula or static value inside the cell
56397
56454
  if (cell.isFormula) {
56398
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
56455
+ const res = addFormula(cell);
56456
+ if (!res) {
56457
+ continue;
56458
+ }
56459
+ ({ attrs: additionalAttrs, node: cellNode } = res);
56399
56460
  }
56400
56461
  else if (cell.content && isMarkdownLink(cell.content)) {
56401
56462
  const { label } = parseMarkdownLink(cell.content);
@@ -57415,6 +57476,6 @@ exports.setTranslationMethod = setTranslationMethod;
57415
57476
  exports.tokenize = tokenize;
57416
57477
 
57417
57478
 
57418
- __info__.version = "17.0.23";
57419
- __info__.date = "2024-05-24T11:27:27.416Z";
57420
- __info__.hash = "6c10fec";
57479
+ __info__.version = "17.0.25";
57480
+ __info__.date = "2024-06-10T09:33:40.022Z";
57481
+ __info__.hash = "1f01394";
@@ -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 17.0.23
6
- * @date 2024-05-24T11:27:27.416Z
7
- * @hash 6c10fec
5
+ * @version 17.0.25
6
+ * @date 2024-06-10T09:33:40.022Z
7
+ * @hash 1f01394
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -392,7 +392,10 @@ function deepCopy(obj) {
392
392
  * Check if the object is a plain old javascript object.
393
393
  */
394
394
  function isPlainObject(obj) {
395
- return typeof obj === "object" && obj?.constructor === Object;
395
+ return (typeof obj === "object" &&
396
+ obj !== null &&
397
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
398
+ (obj?.constructor === Object || obj?.constructor === undefined));
396
399
  }
397
400
  /**
398
401
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -4304,8 +4307,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
4304
4307
  /**
4305
4308
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4306
4309
  */
4307
- function createRange(getters, sheetId, range) {
4308
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4310
+ function createValidRange(getters, sheetId, xc) {
4311
+ if (!xc)
4312
+ return;
4313
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4314
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4309
4315
  }
4310
4316
  /**
4311
4317
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5233,8 +5239,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
5233
5239
  type = "scorecard";
5234
5240
  constructor(definition, sheetId, getters) {
5235
5241
  super(definition, sheetId, getters);
5236
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
5237
- this.baseline = createRange(getters, sheetId, definition.baseline);
5242
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
5243
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
5238
5244
  this.baselineMode = definition.baselineMode;
5239
5245
  this.baselineDescr = definition.baselineDescr;
5240
5246
  this.background = definition.background;
@@ -6705,6 +6711,7 @@ const FilterMenuPopoverBuilder = {
6705
6711
  };
6706
6712
 
6707
6713
  const macRegex = /Mac/i;
6714
+ const MODIFIER_KEYS$1 = ["Shift", "Control", "Alt", "Meta"];
6708
6715
  /**
6709
6716
  * Return true if the event was triggered from
6710
6717
  * a child element.
@@ -6743,6 +6750,31 @@ function* iterateChildren(el) {
6743
6750
  function getOpenedMenus() {
6744
6751
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
6745
6752
  }
6753
+ const letterRegex = /^[a-zA-Z]$/;
6754
+ /**
6755
+ * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
6756
+ *
6757
+ * @argument ev - The keyboard event to transform
6758
+ * @argument mode - Use either ev.key of ev.code to get the string shortcut
6759
+ *
6760
+ * @example
6761
+ * event : { ctrlKey: true, key: "a" } => "Ctrl+A"
6762
+ * event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
6763
+ */
6764
+ function keyboardEventToShortcutString(ev, mode = "key") {
6765
+ let keyDownString = "";
6766
+ if (!MODIFIER_KEYS$1.includes(ev.key)) {
6767
+ if (isCtrlKey(ev))
6768
+ keyDownString += "Ctrl+";
6769
+ if (ev.altKey)
6770
+ keyDownString += "Alt+";
6771
+ if (ev.shiftKey)
6772
+ keyDownString += "Shift+";
6773
+ }
6774
+ const key = mode === "key" ? ev.key : ev.code;
6775
+ keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
6776
+ return keyDownString;
6777
+ }
6746
6778
  function isMacOS() {
6747
6779
  return Boolean(macRegex.test(navigator.userAgent));
6748
6780
  }
@@ -6761,8 +6793,7 @@ function isCtrlKey(ev) {
6761
6793
  */
6762
6794
  function useSpreadsheetRect() {
6763
6795
  const position = useState({ x: 0, y: 0, width: 0, height: 0 });
6764
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
6765
- updatePosition();
6796
+ let spreadsheetElement = null;
6766
6797
  function updatePosition() {
6767
6798
  if (!spreadsheetElement) {
6768
6799
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -8535,7 +8566,7 @@ function chartToImage(runtime, figure, type) {
8535
8566
  if ("chartJsConfig" in runtime) {
8536
8567
  runtime.chartJsConfig.plugins = [backgroundColorChartJSPlugin];
8537
8568
  // @ts-ignore
8538
- const chart = new window.Chart(canvas, runtime.chartJsConfig);
8569
+ const chart = new window.Chart(canvas, deepCopy(runtime.chartJsConfig));
8539
8570
  const imgContent = chart.toBase64Image();
8540
8571
  chart.destroy();
8541
8572
  div.remove();
@@ -8579,7 +8610,7 @@ class BarChart extends AbstractChart {
8579
8610
  constructor(definition, sheetId, getters) {
8580
8611
  super(definition, sheetId, getters);
8581
8612
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
8582
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
8613
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
8583
8614
  this.background = definition.background;
8584
8615
  this.verticalAxisPosition = definition.verticalAxisPosition;
8585
8616
  this.legendPosition = definition.legendPosition;
@@ -8822,7 +8853,7 @@ class GaugeChart extends AbstractChart {
8822
8853
  type = "gauge";
8823
8854
  constructor(definition, sheetId, getters) {
8824
8855
  super(definition, sheetId, getters);
8825
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
8856
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
8826
8857
  this.sectionRule = definition.sectionRule;
8827
8858
  this.background = definition.background;
8828
8859
  }
@@ -9156,7 +9187,7 @@ class LineChart extends AbstractChart {
9156
9187
  constructor(definition, sheetId, getters) {
9157
9188
  super(definition, sheetId, getters);
9158
9189
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9159
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
9190
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
9160
9191
  this.background = definition.background;
9161
9192
  this.verticalAxisPosition = definition.verticalAxisPosition;
9162
9193
  this.legendPosition = definition.legendPosition;
@@ -9476,7 +9507,7 @@ class PieChart extends AbstractChart {
9476
9507
  constructor(definition, sheetId, getters) {
9477
9508
  super(definition, sheetId, getters);
9478
9509
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9479
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
9510
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
9480
9511
  this.background = definition.background;
9481
9512
  this.legendPosition = definition.legendPosition;
9482
9513
  this.aggregated = definition.aggregated;
@@ -21723,7 +21754,7 @@ class LineBarPieConfigPanel extends Component {
21723
21754
  }
21724
21755
  const getters = this.env.model.getters;
21725
21756
  const sheetId = getters.getActiveSheetId();
21726
- const labelRange = createRange(getters, sheetId, this.labelRange);
21757
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
21727
21758
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
21728
21759
  if (dataSets.length) {
21729
21760
  return dataSets[0].dataRange.zone.top + 1;
@@ -25765,14 +25796,14 @@ class FigureComponent extends Component {
25765
25796
  }
25766
25797
  onKeyDown(ev) {
25767
25798
  const figure = this.props.figure;
25768
- switch (ev.key) {
25799
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
25800
+ switch (keyDownShortcut) {
25769
25801
  case "Delete":
25770
25802
  this.env.model.dispatch("DELETE_FIGURE", {
25771
25803
  sheetId: this.env.model.getters.getActiveSheetId(),
25772
25804
  id: figure.id,
25773
25805
  });
25774
25806
  this.props.onFigureDeleted();
25775
- ev.stopPropagation();
25776
25807
  ev.preventDefault();
25777
25808
  ev.stopPropagation();
25778
25809
  break;
@@ -25793,7 +25824,22 @@ class FigureComponent extends Component {
25793
25824
  x: figure.x + delta[0],
25794
25825
  y: figure.y + delta[1],
25795
25826
  });
25827
+ ev.preventDefault();
25828
+ ev.stopPropagation();
25829
+ break;
25830
+ case "Ctrl+A":
25831
+ // Maybe in the future we will implement a way to select all figures
25832
+ ev.preventDefault();
25796
25833
  ev.stopPropagation();
25834
+ break;
25835
+ case "Ctrl+Y":
25836
+ case "Ctrl+Z":
25837
+ if (keyDownShortcut === "Ctrl+Y") {
25838
+ this.env.model.dispatch("REQUEST_REDO");
25839
+ }
25840
+ else if (keyDownShortcut === "Ctrl+Z") {
25841
+ this.env.model.dispatch("REQUEST_UNDO");
25842
+ }
25797
25843
  ev.preventDefault();
25798
25844
  ev.stopPropagation();
25799
25845
  break;
@@ -26813,8 +26859,15 @@ class Composer extends Component {
26813
26859
  }
26814
26860
  onPaste(ev) {
26815
26861
  if (this.env.model.getters.getEditionMode() !== "inactive") {
26862
+ // let the browser clipboard work
26816
26863
  ev.stopPropagation();
26817
26864
  }
26865
+ else {
26866
+ // the user meant to paste in the sheet, not open the composer with the pasted content
26867
+ // While we're not editing, we still have the focus and should therefore prevent
26868
+ // the native "paste" to occur.
26869
+ ev.preventDefault();
26870
+ }
26818
26871
  }
26819
26872
  /*
26820
26873
  * Triggered automatically by the content-editable between the keydown and key up
@@ -26823,10 +26876,6 @@ class Composer extends Component {
26823
26876
  if (!this.shouldProcessInputEvents) {
26824
26877
  return;
26825
26878
  }
26826
- if (ev.inputType === "insertFromPaste" &&
26827
- this.env.model.getters.getEditionMode() === "inactive") {
26828
- return;
26829
- }
26830
26879
  ev.stopPropagation();
26831
26880
  let content;
26832
26881
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -27274,10 +27323,7 @@ class GridComposer extends Component {
27274
27323
  }
27275
27324
  get containerStyle() {
27276
27325
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27277
- return `
27278
- position: absolute;
27279
- z-index: -1000;
27280
- `;
27326
+ return `z-index: -1000;`;
27281
27327
  }
27282
27328
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27283
27329
  const cell = this.env.model.getters.getActiveCell();
@@ -38570,6 +38616,9 @@ class RangeAdapter {
38570
38616
  if (range.invalidXc) {
38571
38617
  return range.invalidXc;
38572
38618
  }
38619
+ if (!this.getters.tryGetSheet(range.sheetId)) {
38620
+ return INCORRECT_RANGE_STRING;
38621
+ }
38573
38622
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
38574
38623
  return INCORRECT_RANGE_STRING;
38575
38624
  }
@@ -42021,16 +42070,22 @@ class EvaluationPlugin extends UIPlugin {
42021
42070
  let newContent = undefined;
42022
42071
  let newFormat = undefined;
42023
42072
  let isExported = true;
42073
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42024
42074
  const formulaCell = this.getCorrespondingFormulaCell(position);
42025
42075
  if (formulaCell) {
42026
42076
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
42027
42077
  isFormula = isExported;
42028
42078
  if (!isExported) {
42029
- newContent = value.toString();
42030
- newFormat = evaluatedCell.format;
42079
+ // If the cell contains a non-exported formula and that is evaluates to
42080
+ // nothing* ,we don't export it.
42081
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
42082
+ // the empty string.
42083
+ if (value !== "") {
42084
+ newContent = value.toString();
42085
+ newFormat = evaluatedCell.format;
42086
+ }
42031
42087
  }
42032
42088
  }
42033
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42034
42089
  const exportedCellData = exportedSheetData.cells[xc] || {};
42035
42090
  const format = newFormat
42036
42091
  ? getItemId(newFormat, data.formats)
@@ -51642,9 +51697,11 @@ class BottomBarSheet extends Component {
51642
51697
  if (ev.key === "Enter") {
51643
51698
  ev.preventDefault();
51644
51699
  this.stopEdition();
51700
+ this.env.focusableElement.focus();
51645
51701
  }
51646
51702
  if (ev.key === "Escape") {
51647
51703
  this.cancelEdition();
51704
+ this.env.focusableElement.focus();
51648
51705
  }
51649
51706
  }
51650
51707
  onClickSheetName(ev) {
@@ -56393,7 +56450,11 @@ function addRows(construct, data, sheet) {
56393
56450
  let cellNode = escapeXml ``;
56394
56451
  // Either formula or static value inside the cell
56395
56452
  if (cell.isFormula) {
56396
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
56453
+ const res = addFormula(cell);
56454
+ if (!res) {
56455
+ continue;
56456
+ }
56457
+ ({ attrs: additionalAttrs, node: cellNode } = res);
56397
56458
  }
56398
56459
  else if (cell.content && isMarkdownLink(cell.content)) {
56399
56460
  const { label } = parseMarkdownLink(cell.content);
@@ -57378,6 +57439,6 @@ const constants = {
57378
57439
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
57379
57440
 
57380
57441
 
57381
- __info__.version = "17.0.23";
57382
- __info__.date = "2024-05-24T11:27:27.416Z";
57383
- __info__.hash = "6c10fec";
57442
+ __info__.version = "17.0.25";
57443
+ __info__.date = "2024-06-10T09:33:40.022Z";
57444
+ __info__.hash = "1f01394";