@odoo/o-spreadsheet 16.2.29 → 16.2.31

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.
@@ -1691,6 +1691,9 @@ function parseFormat(formatString) {
1691
1691
  function formatValue(value, format) {
1692
1692
  switch (typeof value) {
1693
1693
  case "string":
1694
+ if (value.includes('\\"')) {
1695
+ return value.replace(/\\"/g, '"');
1696
+ }
1694
1697
  return value;
1695
1698
  case "boolean":
1696
1699
  return value ? "TRUE" : "FALSE";
@@ -6271,14 +6274,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
6271
6274
  : undefined));
6272
6275
  }
6273
6276
  }
6274
- else if (zone.left === zone.right && zone.top === zone.bottom) {
6275
- // A single cell. If it's only the title, the dataset is not added.
6276
- if (!dataSetsHaveTitle) {
6277
- dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
6278
- }
6279
- }
6280
6277
  else {
6281
- /* 1 row or 1 column */
6278
+ /* 1 cell, 1 row or 1 column */
6282
6279
  dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
6283
6280
  ? {
6284
6281
  top: zone.top,
@@ -6328,8 +6325,10 @@ function toExcelDataset(getters, ds) {
6328
6325
  }
6329
6326
  const dataRange = ds.dataRange.clone({ zone: dataZone });
6330
6327
  return {
6331
- label: ds.labelCell ? getters.getRangeString(ds.labelCell, "forceSheetReference") : undefined,
6332
- range: getters.getRangeString(dataRange, "forceSheetReference"),
6328
+ label: ds.labelCell
6329
+ ? getters.getRangeString(ds.labelCell, "forceSheetReference", true)
6330
+ : undefined,
6331
+ range: getters.getRangeString(dataRange, "forceSheetReference", true),
6333
6332
  };
6334
6333
  }
6335
6334
  /**
@@ -6854,6 +6853,9 @@ class BarChart extends AbstractChart {
6854
6853
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
6855
6854
  return {
6856
6855
  ...this.getDefinition(),
6856
+ labelRange: this.labelRange
6857
+ ? this.getters.getRangeString(this.labelRange, this.sheetId, true)
6858
+ : undefined,
6857
6859
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
6858
6860
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
6859
6861
  dataSets,
@@ -7418,6 +7420,9 @@ class LineChart extends AbstractChart {
7418
7420
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
7419
7421
  return {
7420
7422
  ...this.getDefinition(),
7423
+ labelRange: this.labelRange
7424
+ ? this.getters.getRangeString(this.labelRange, this.sheetId, true)
7425
+ : undefined,
7421
7426
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
7422
7427
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
7423
7428
  dataSets,
@@ -7691,6 +7696,9 @@ class PieChart extends AbstractChart {
7691
7696
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
7692
7697
  return {
7693
7698
  ...this.getDefinition(),
7699
+ labelRange: this.labelRange
7700
+ ? this.getters.getRangeString(this.labelRange, this.sheetId, true)
7701
+ : undefined,
7694
7702
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
7695
7703
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
7696
7704
  verticalAxisPosition: "left",
@@ -9134,6 +9142,12 @@ const INSERT_LINK = (env) => {
9134
9142
  let { col, row } = env.model.getters.getActivePosition();
9135
9143
  env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
9136
9144
  };
9145
+ const INSERT_LINK_NAME = (env) => {
9146
+ const sheetId = env.model.getters.getActiveSheetId();
9147
+ const { col, row } = env.model.getters.getActivePosition();
9148
+ const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
9149
+ return cell && cell.link ? _lt("Edit link") : _lt("Insert link");
9150
+ };
9137
9151
  //------------------------------------------------------------------------------
9138
9152
  // Filters action
9139
9153
  //------------------------------------------------------------------------------
@@ -9271,7 +9285,7 @@ cellMenuRegistry
9271
9285
  action: DELETE_CELL_SHIFT_LEFT,
9272
9286
  })
9273
9287
  .add("insert_link", {
9274
- name: _lt("Insert link"),
9288
+ name: INSERT_LINK_NAME,
9275
9289
  separator: true,
9276
9290
  sequence: 150,
9277
9291
  action: INSERT_LINK,
@@ -19957,14 +19971,13 @@ class Composer extends Component {
19957
19971
  setup() {
19958
19972
  onMounted(() => {
19959
19973
  const el = this.composerRef.el;
19974
+ if (this.props.isDefaultFocus) {
19975
+ this.env.focusableElement.setFocusableElement(el);
19976
+ }
19960
19977
  this.contentHelper.updateEl(el);
19961
19978
  this.processContent();
19962
19979
  this.contentHelper.scrollSelectionIntoView();
19963
19980
  });
19964
- onWillUnmount(() => {
19965
- var _a, _b;
19966
- (_b = (_a = this.props).onComposerUnmounted) === null || _b === void 0 ? void 0 : _b.call(_a);
19967
- });
19968
19981
  onPatched(() => {
19969
19982
  if (!this.isKeyStillDown) {
19970
19983
  this.processContent();
@@ -19975,7 +19988,8 @@ class Composer extends Component {
19975
19988
  // Handlers
19976
19989
  // ---------------------------------------------------------------------------
19977
19990
  processArrowKeys(ev) {
19978
- if (this.env.model.getters.isSelectingForComposer()) {
19991
+ if (this.env.model.getters.isSelectingForComposer() ||
19992
+ this.env.model.getters.getEditionMode() === "inactive") {
19979
19993
  this.functionDescriptionState.showDescription = false;
19980
19994
  // Prevent the default content editable behavior which moves the cursor
19981
19995
  ev.preventDefault();
@@ -20016,21 +20030,23 @@ class Composer extends Component {
20016
20030
  var _a;
20017
20031
  ev.preventDefault();
20018
20032
  ev.stopPropagation();
20019
- if (this.autoCompleteState.showProvider) {
20020
- const autoCompleteValue = (_a = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]) === null || _a === void 0 ? void 0 : _a.text;
20021
- if (autoCompleteValue) {
20022
- this.autoComplete(autoCompleteValue);
20023
- return;
20033
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
20034
+ if (this.autoCompleteState.showProvider) {
20035
+ const autoCompleteValue = (_a = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]) === null || _a === void 0 ? void 0 : _a.text;
20036
+ if (autoCompleteValue) {
20037
+ this.autoComplete(autoCompleteValue);
20038
+ return;
20039
+ }
20024
20040
  }
20025
- }
20026
- else {
20027
- // when completing with tab, if there is no value to complete, the active cell will be moved to the right.
20028
- // we can't let the model think that it is for a ref selection.
20029
- // todo: check if this can be removed someday
20030
- this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
20041
+ else {
20042
+ // when completing with tab, if there is no value to complete, the active cell will be moved to the right.
20043
+ // we can't let the model think that it is for a ref selection.
20044
+ // todo: check if this can be removed someday
20045
+ this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
20046
+ }
20047
+ this.env.model.dispatch("STOP_EDITION");
20031
20048
  }
20032
20049
  const direction = ev.shiftKey ? "left" : "right";
20033
- this.env.model.dispatch("STOP_EDITION");
20034
20050
  this.env.model.selection.moveAnchorCell(direction, 1);
20035
20051
  }
20036
20052
  processEnterKey(ev) {
@@ -20075,6 +20091,9 @@ class Composer extends Component {
20075
20091
  this.compositionActive = false;
20076
20092
  }
20077
20093
  onKeydown(ev) {
20094
+ if (this.env.model.getters.getEditionMode() === "inactive") {
20095
+ return;
20096
+ }
20078
20097
  let handler = this.keyMapping[ev.key];
20079
20098
  if (handler) {
20080
20099
  handler.call(this, ev);
@@ -20085,22 +20104,45 @@ class Composer extends Component {
20085
20104
  }
20086
20105
  }
20087
20106
  updateCursorIfNeeded() {
20088
- if (!this.env.model.getters.isSelectingForComposer()) {
20107
+ const moveCursor = !this.env.model.getters.isSelectingForComposer() &&
20108
+ !(this.env.model.getters.getEditionMode() === "inactive");
20109
+ if (moveCursor) {
20089
20110
  const { start, end } = this.contentHelper.getCurrentSelection();
20090
20111
  this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
20091
20112
  this.isKeyStillDown = true;
20092
20113
  }
20093
20114
  }
20115
+ onPaste(ev) {
20116
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
20117
+ ev.stopPropagation();
20118
+ }
20119
+ }
20094
20120
  /*
20095
20121
  * Triggered automatically by the content-editable between the keydown and key up
20096
20122
  * */
20097
- onInput() {
20098
- if (this.props.focus === "inactive" || !this.shouldProcessInputEvents) {
20123
+ onInput(ev) {
20124
+ var _a, _b;
20125
+ if (!this.shouldProcessInputEvents) {
20126
+ return;
20127
+ }
20128
+ if (ev.inputType === "insertFromPaste" &&
20129
+ this.env.model.getters.getEditionMode() === "inactive") {
20099
20130
  return;
20100
20131
  }
20132
+ ev.stopPropagation();
20133
+ let content;
20134
+ if (this.env.model.getters.getEditionMode() === "inactive") {
20135
+ content = ev.data || "";
20136
+ }
20137
+ else {
20138
+ content = this.contentHelper.getText();
20139
+ }
20140
+ if (this.props.focus === "inactive") {
20141
+ return (_b = (_a = this.props).onComposerCellFocused) === null || _b === void 0 ? void 0 : _b.call(_a, content);
20142
+ }
20101
20143
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
20102
20144
  this.env.model.dispatch("SET_CURRENT_CONTENT", {
20103
- content: this.contentHelper.getText(),
20145
+ content,
20104
20146
  selection: this.contentHelper.getCurrentSelection(),
20105
20147
  });
20106
20148
  }
@@ -20171,9 +20213,8 @@ class Composer extends Component {
20171
20213
  }
20172
20214
  const newSelection = this.contentHelper.getCurrentSelection();
20173
20215
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
20174
- if (this.props.focus === "inactive") {
20175
- this.props.onComposerContentFocused(newSelection);
20176
- }
20216
+ this.props.onComposerContentFocused();
20217
+ if (this.props.focus === "inactive") ;
20177
20218
  this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
20178
20219
  this.processTokenAtCursor();
20179
20220
  }
@@ -20397,14 +20438,16 @@ Composer.template = "o-spreadsheet-Composer";
20397
20438
  Composer.components = { TextValueProvider, FunctionDescriptionProvider };
20398
20439
  Composer.defaultProps = {
20399
20440
  inputStyle: "",
20441
+ isDefaultFocus: false,
20400
20442
  };
20401
20443
  Composer.props = {
20402
- focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
20403
- onComposerContentFocused: Function,
20404
20444
  inputStyle: { type: String, optional: true },
20405
20445
  rect: { type: Object, optional: true },
20406
20446
  delimitation: { type: Object, optional: true },
20407
- onComposerUnmounted: { type: Function, optional: true },
20447
+ focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
20448
+ onComposerCellFocused: { type: Function, optional: true },
20449
+ onComposerContentFocused: Function,
20450
+ isDefaultFocus: { type: Boolean, optional: true },
20408
20451
  };
20409
20452
 
20410
20453
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
@@ -20436,46 +20479,28 @@ css /* scss */ `
20436
20479
  * It also applies the style of the cell to the composer input.
20437
20480
  */
20438
20481
  class GridComposer extends Component {
20482
+ constructor() {
20483
+ super(...arguments);
20484
+ // TODORAR see if we can keep it undefined
20485
+ this.rect = this.defaultRect;
20486
+ this.isEditing = false;
20487
+ }
20488
+ get defaultRect() {
20489
+ return { x: 0, y: 0, width: 0, height: 0 };
20490
+ }
20439
20491
  setup() {
20440
- this.gridComposerRef = useRef("gridComposer");
20441
- this.composerState = useState({
20442
- rect: undefined,
20443
- delimitation: undefined,
20444
- });
20445
- const { sheetId, col, row } = this.env.model.getters.getActivePosition();
20446
- this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
20447
- this.rect = this.env.model.getters.getVisibleRect(this.zone);
20448
- this.isCellReferenceVisible = false;
20449
- onMounted(() => {
20450
- const el = this.gridComposerRef.el;
20451
- this.composerState.rect = {
20452
- x: this.rect.x,
20453
- y: this.rect.y,
20454
- width: el.clientWidth,
20455
- height: el.clientHeight,
20456
- };
20457
- this.composerState.delimitation = {
20458
- width: el.parentElement.clientWidth,
20459
- height: el.parentElement.clientHeight,
20460
- };
20461
- });
20462
20492
  onWillUpdateProps(() => {
20463
- if (this.isCellReferenceVisible) {
20464
- return;
20465
- }
20466
- const sheetId = this.env.model.getters.getActiveSheetId();
20467
- const zone = this.env.model.getters.getSelectedZone();
20468
- const rect = this.env.model.getters.getVisibleRect(zone);
20469
- if (!deepEquals(rect, this.rect) ||
20470
- sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
20471
- this.isCellReferenceVisible = true;
20472
- }
20493
+ this.updateComponentPosition();
20494
+ this.updateCellReferenceVisibility();
20473
20495
  });
20474
20496
  }
20475
20497
  get shouldDisplayCellReference() {
20476
20498
  return this.isCellReferenceVisible;
20477
20499
  }
20478
20500
  get cellReference() {
20501
+ if (!this.env.model.getters.getCurrentEditedCell()) {
20502
+ return "";
20503
+ }
20479
20504
  const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
20480
20505
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
20481
20506
  return `${prefixSheet ? getComposerSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
@@ -20487,7 +20512,27 @@ class GridComposer extends Component {
20487
20512
  top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
20488
20513
  });
20489
20514
  }
20515
+ get composerProps() {
20516
+ const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
20517
+ return {
20518
+ rect: { ...this.rect },
20519
+ delimitation: {
20520
+ width,
20521
+ height,
20522
+ },
20523
+ focus: this.props.focus,
20524
+ isDefaultFocus: true,
20525
+ onComposerContentFocused: this.props.onComposerContentFocused,
20526
+ onComposerCellFocused: this.props.onComposerCellFocused,
20527
+ };
20528
+ }
20490
20529
  get containerStyle() {
20530
+ if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
20531
+ return `
20532
+ position: absolute;
20533
+ z-index: -1000;
20534
+ `;
20535
+ }
20491
20536
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
20492
20537
  const cell = this.env.model.getters.getActiveCell();
20493
20538
  const position = this.env.model.getters.getActivePosition();
@@ -20507,6 +20552,8 @@ class GridComposer extends Component {
20507
20552
  if (!isFormula) {
20508
20553
  textAlign = style.align || cell.defaultAlign;
20509
20554
  }
20555
+ const maxHeight = this.props.gridDims.height - this.rect.y;
20556
+ const maxWidth = this.props.gridDims.width - this.rect.x;
20510
20557
  /**
20511
20558
  * min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
20512
20559
  * including all the paddings/margins of the composer
@@ -20518,6 +20565,8 @@ class GridComposer extends Component {
20518
20565
  top: `${top}px`,
20519
20566
  "min-width": `${width + 1}px`,
20520
20567
  "min-height": `${height + 1}px`,
20568
+ "max-width": `${maxWidth}px`,
20569
+ "max-height": `${maxHeight}px`,
20521
20570
  background,
20522
20571
  color,
20523
20572
  "font-size": `${fontSizeInPixels(fontSize)}px`,
@@ -20527,22 +20576,40 @@ class GridComposer extends Component {
20527
20576
  "text-align": textAlign,
20528
20577
  });
20529
20578
  }
20530
- get composerStyle() {
20531
- const maxHeight = this.props.gridDims.height - this.rect.y;
20532
- const maxWidth = this.props.gridDims.width - this.rect.x;
20533
- return cssPropertiesToCss({
20534
- "max-width": `${maxWidth}px`,
20535
- "max-height": `${maxHeight}px`,
20536
- });
20579
+ updateComponentPosition() {
20580
+ const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
20581
+ if (this.isEditing !== isEditing) {
20582
+ this.isEditing = isEditing;
20583
+ if (!isEditing) {
20584
+ this.rect = this.defaultRect;
20585
+ this.env.focusableElement.focus();
20586
+ return;
20587
+ }
20588
+ const position = this.env.model.getters.getActivePosition();
20589
+ const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
20590
+ this.rect = this.env.model.getters.getVisibleRect(zone);
20591
+ }
20592
+ }
20593
+ updateCellReferenceVisibility() {
20594
+ if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
20595
+ return;
20596
+ }
20597
+ const sheetId = this.env.model.getters.getActiveSheetId();
20598
+ const zone = this.env.model.getters.getSelectedZone();
20599
+ const rect = this.env.model.getters.getVisibleRect(zone);
20600
+ if (!deepEquals(rect, this.rect) ||
20601
+ sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
20602
+ this.isCellReferenceVisible = true;
20603
+ }
20537
20604
  }
20538
20605
  }
20539
20606
  GridComposer.template = "o-spreadsheet-GridComposer";
20540
20607
  GridComposer.components = { Composer };
20541
20608
  GridComposer.props = {
20542
20609
  focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
20543
- onComposerUnmounted: Function,
20544
20610
  onComposerContentFocused: Function,
20545
20611
  gridDims: Object,
20612
+ onComposerCellFocused: Function,
20546
20613
  };
20547
20614
 
20548
20615
  const CSS$1 = css /* scss */ `
@@ -21133,7 +21200,6 @@ class GridOverlay extends Component {
21133
21200
  this.props.onCellDoubleClicked(col, row);
21134
21201
  }
21135
21202
  onContextMenu(ev) {
21136
- ev.preventDefault();
21137
21203
  const [col, row] = this.getCartesianCoordinates(ev);
21138
21204
  this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
21139
21205
  }
@@ -22360,17 +22426,16 @@ class Grid extends Component {
22360
22426
  menuItems: [],
22361
22427
  });
22362
22428
  this.gridRef = useRef("grid");
22363
- this.hiddenInput = useRef("hiddenInput");
22364
22429
  this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
22365
22430
  this.hoveredCell = useState({ col: undefined, row: undefined });
22366
22431
  useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
22367
22432
  useExternalListener(document.body, "cut", this.copy.bind(this, true));
22368
22433
  useExternalListener(document.body, "copy", this.copy.bind(this, false));
22369
22434
  useExternalListener(document.body, "paste", this.paste);
22370
- onMounted(() => this.focus());
22371
- this.props.exposeFocus(() => this.focus());
22435
+ onMounted(() => this.focusDefaultElement());
22436
+ this.props.exposeFocus(() => this.focusDefaultElement());
22372
22437
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
22373
- useEffect(() => this.focus(), () => [this.env.model.getters.getActiveSheetId()]);
22438
+ useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
22374
22439
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
22375
22440
  this.moveCanvas(deltaX, deltaY);
22376
22441
  this.hoveredCell.col = undefined;
@@ -22393,13 +22458,12 @@ class Grid extends Component {
22393
22458
  if (this.env.model.getters.hasOpenedPopover()) {
22394
22459
  this.closeOpenedPopover();
22395
22460
  }
22396
- this.focus();
22461
+ this.focusDefaultElement();
22397
22462
  }
22398
- focus() {
22399
- var _a;
22463
+ focusDefaultElement() {
22400
22464
  if (!this.env.model.getters.getSelectedFigureId() &&
22401
22465
  this.env.model.getters.getEditionMode() === "inactive") {
22402
- (_a = this.hiddenInput.el) === null || _a === void 0 ? void 0 : _a.focus();
22466
+ this.env.focusableElement.focus();
22403
22467
  }
22404
22468
  }
22405
22469
  get gridEl() {
@@ -22544,19 +22608,6 @@ class Grid extends Component {
22544
22608
  return;
22545
22609
  }
22546
22610
  }
22547
- onInput(ev) {
22548
- // the user meant to paste in the sheet, not open the composer with the pasted content
22549
- if (!ev.isComposing && ev.inputType === "insertFromPaste") {
22550
- return;
22551
- }
22552
- if (ev.data) {
22553
- // if the user types a character on the grid, it means he wants to start composing the selected cell with that
22554
- // character
22555
- ev.preventDefault();
22556
- ev.stopPropagation();
22557
- this.props.onGridComposerCellFocused(ev.data);
22558
- }
22559
- }
22560
22611
  // ---------------------------------------------------------------------------
22561
22612
  // Context Menu
22562
22613
  // ---------------------------------------------------------------------------
@@ -22653,7 +22704,7 @@ class Grid extends Component {
22653
22704
  }
22654
22705
  closeMenu() {
22655
22706
  this.menuState.isOpen = false;
22656
- this.focus();
22707
+ this.focusDefaultElement();
22657
22708
  }
22658
22709
  }
22659
22710
  Grid.template = "o-spreadsheet-Grid";
@@ -27005,7 +27056,7 @@ function normalizeV9(formula) {
27005
27056
  * a breaking change is made in the way the state is handled, and an upgrade
27006
27057
  * function should be defined
27007
27058
  */
27008
- const CURRENT_VERSION = 12;
27059
+ const CURRENT_VERSION = 12.5;
27009
27060
  const INITIAL_SHEET_ID = "Sheet1";
27010
27061
  /**
27011
27062
  * This function tries to load anything that could look like a valid
@@ -27271,6 +27322,31 @@ const MIGRATIONS = [
27271
27322
  return data;
27272
27323
  },
27273
27324
  },
27325
+ {
27326
+ description: "Fix datafilter duplication",
27327
+ from: 12,
27328
+ to: 12.5,
27329
+ applyMigration(data) {
27330
+ for (let sheet of data.sheets || []) {
27331
+ let knownDataFilterZones = [];
27332
+ for (let filterTable of sheet.filterTables || []) {
27333
+ const zone = toZone(filterTable.range);
27334
+ // See commit message for the details
27335
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
27336
+ if (intersectZoneIndex !== -1) {
27337
+ knownDataFilterZones[intersectZoneIndex] = zone;
27338
+ }
27339
+ else {
27340
+ knownDataFilterZones.push(zone);
27341
+ }
27342
+ }
27343
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
27344
+ range: zoneToXc(zone),
27345
+ }));
27346
+ }
27347
+ return data;
27348
+ },
27349
+ },
27274
27350
  ];
27275
27351
  /**
27276
27352
  * This function is used to repair faulty data independently of the migration.
@@ -28291,13 +28367,13 @@ class CellPlugin extends CorePlugin {
28291
28367
  /*
28292
28368
  * Reconstructs the original formula string based on a normalized form and its dependencies
28293
28369
  */
28294
- buildFormulaContent(sheetId, cell, dependencies) {
28370
+ buildFormulaContent(sheetId, cell, dependencies, useFixedZone = false) {
28295
28371
  const ranges = dependencies || cell.dependencies;
28296
28372
  let rangeIndex = 0;
28297
28373
  return concat(cell.compiledFormula.tokens.map((token) => {
28298
28374
  if (token.type === "REFERENCE") {
28299
28375
  const range = ranges[rangeIndex++];
28300
- return this.getters.getRangeString(range, sheetId);
28376
+ return this.getters.getRangeString(range, sheetId, useFixedZone);
28301
28377
  }
28302
28378
  return token.value;
28303
28379
  }));
@@ -28867,7 +28943,13 @@ class ConditionalFormatPlugin extends CorePlugin {
28867
28943
  }
28868
28944
  }
28869
28945
  exportForExcel(data) {
28870
- this.export(data);
28946
+ if (data.sheets) {
28947
+ for (let sheet of data.sheets) {
28948
+ if (this.cfRules[sheet.id]) {
28949
+ sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useFixedReference: true }));
28950
+ }
28951
+ }
28952
+ }
28871
28953
  }
28872
28954
  // ---------------------------------------------------------------------------
28873
28955
  // Getters
@@ -28917,11 +28999,11 @@ class ConditionalFormatPlugin extends CorePlugin {
28917
28999
  // ---------------------------------------------------------------------------
28918
29000
  // Private
28919
29001
  // ---------------------------------------------------------------------------
28920
- mapToConditionalFormat(sheetId, cf) {
29002
+ mapToConditionalFormat(sheetId, cf, options = { useFixedReference: false }) {
28921
29003
  return {
28922
29004
  ...cf,
28923
29005
  ranges: cf.ranges.map((range) => {
28924
- return this.getters.getRangeString(range, sheetId);
29006
+ return this.getters.getRangeString(range, sheetId, options.useFixedReference);
28925
29007
  }),
28926
29008
  };
28927
29009
  }
@@ -30850,8 +30932,9 @@ class RangeAdapter {
30850
30932
  *
30851
30933
  * @param range the range (received from getRangeFromXC or getRangeFromZone)
30852
30934
  * @param forSheetId the id of the sheet where the range string is supposed to be used.
30935
+ * @param [useFixedZone=false] if true, the range will be returned with fixed row and column
30853
30936
  */
30854
- getRangeString(range, forSheetId) {
30937
+ getRangeString(range, forSheetId, useFixedZone = false) {
30855
30938
  if (!range) {
30856
30939
  return INCORRECT_RANGE_STRING;
30857
30940
  }
@@ -30878,7 +30961,7 @@ class RangeAdapter {
30878
30961
  if (prefixSheet && !sheetName) {
30879
30962
  return INCORRECT_RANGE_STRING;
30880
30963
  }
30881
- let rangeString = this.getRangePartString(rangeImpl, 0);
30964
+ let rangeString = this.getRangePartString(rangeImpl, 0, useFixedZone);
30882
30965
  if (rangeImpl.parts && rangeImpl.parts.length === 2) {
30883
30966
  // this if converts A2:A2 into A2 except if any part of the original range had fixed row or column (with $)
30884
30967
  if (rangeImpl.zone.top !== rangeImpl.zone.bottom ||
@@ -30888,7 +30971,7 @@ class RangeAdapter {
30888
30971
  rangeImpl.parts[1].rowFixed ||
30889
30972
  rangeImpl.parts[1].colFixed) {
30890
30973
  rangeString += ":";
30891
- rangeString += this.getRangePartString(rangeImpl, 1);
30974
+ rangeString += this.getRangePartString(rangeImpl, 1, useFixedZone);
30892
30975
  }
30893
30976
  }
30894
30977
  return `${prefixSheet ? sheetName + "!" : ""}${rangeString}`;
@@ -30918,14 +31001,14 @@ class RangeAdapter {
30918
31001
  /**
30919
31002
  * Get a Xc string that represent a part of a range
30920
31003
  */
30921
- getRangePartString(range, part) {
31004
+ getRangePartString(range, part, useFixedZone = false) {
30922
31005
  var _a, _b;
30923
31006
  const colFixed = range.parts && ((_a = range.parts[part]) === null || _a === void 0 ? void 0 : _a.colFixed) ? "$" : "";
30924
31007
  const col = part === 0 ? numberToLetters(range.zone.left) : numberToLetters(range.zone.right);
30925
31008
  const rowFixed = range.parts && ((_b = range.parts[part]) === null || _b === void 0 ? void 0 : _b.rowFixed) ? "$" : "";
30926
31009
  const row = part === 0 ? String(range.zone.top + 1) : String(range.zone.bottom + 1);
30927
31010
  let str = "";
30928
- if (range.isFullCol) {
31011
+ if (range.isFullCol && !useFixedZone) {
30929
31012
  if (part === 0 && range.unboundedZone.hasHeader) {
30930
31013
  str = colFixed + col + rowFixed + row;
30931
31014
  }
@@ -30933,7 +31016,7 @@ class RangeAdapter {
30933
31016
  str = colFixed + col;
30934
31017
  }
30935
31018
  }
30936
- else if (range.isFullRow) {
31019
+ else if (range.isFullRow && !useFixedZone) {
30937
31020
  if (part === 0 && range.unboundedZone.hasHeader) {
30938
31021
  str = colFixed + col + rowFixed + row;
30939
31022
  }
@@ -32322,6 +32405,10 @@ class EvaluationPlugin extends UIPlugin {
32322
32405
  if (cell.format !== evaluatedCell.format) {
32323
32406
  exportedCellData.computedFormat = evaluatedCell.format;
32324
32407
  }
32408
+ // if there is a formula but no dependencies (maybe because the cell is in error), no need to recompute the formula text
32409
+ if (cell.isFormula && cell.dependencies.length) {
32410
+ exportedCellData.content = this.getters.buildFormulaContent(sheet.id, cell, cell.dependencies, true);
32411
+ }
32325
32412
  }
32326
32413
  }
32327
32414
  }
@@ -39913,6 +40000,19 @@ class ImageProvider {
39913
40000
  }
39914
40001
  }
39915
40002
 
40003
+ class FocusableElement {
40004
+ constructor() {
40005
+ this.focusableElement = undefined;
40006
+ }
40007
+ setFocusableElement(element) {
40008
+ this.focusableElement = element;
40009
+ }
40010
+ focus() {
40011
+ var _a;
40012
+ (_a = this.focusableElement) === null || _a === void 0 ? void 0 : _a.focus();
40013
+ }
40014
+ }
40015
+
39916
40016
  const RIPPLE_KEY_FRAMES = [
39917
40017
  { transform: "scale(0)" },
39918
40018
  { transform: "scale(0.8)", offset: 0.33 },
@@ -41888,6 +41988,7 @@ class Spreadsheet extends Component {
41888
41988
  _t: Spreadsheet._t,
41889
41989
  clipboard: this.env.clipboard || instantiateClipboard(),
41890
41990
  startCellEdition: (content) => this.onGridComposerCellFocused(content),
41991
+ focusableElement: new FocusableElement(),
41891
41992
  });
41892
41993
  useExternalListener(window, "resize", () => this.render(true));
41893
41994
  useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
@@ -41986,17 +42087,18 @@ class Spreadsheet extends Component {
41986
42087
  this.model.dispatch("UNFOCUS_SELECTION_INPUT");
41987
42088
  this.composer.topBarFocus = "contentFocus";
41988
42089
  this.composer.gridFocusMode = "inactive";
41989
- this.setComposerContent({ selection } || {});
42090
+ this.setComposerContent({ selection });
41990
42091
  }
41991
- onGridComposerContentFocused() {
42092
+ onGridComposerContentFocused(selection) {
41992
42093
  if (this.model.getters.isReadonly()) {
41993
42094
  return;
41994
42095
  }
41995
42096
  this.model.dispatch("UNFOCUS_SELECTION_INPUT");
41996
42097
  this.composer.topBarFocus = "inactive";
41997
42098
  this.composer.gridFocusMode = "contentFocus";
41998
- this.setComposerContent({});
42099
+ this.setComposerContent({ selection });
41999
42100
  }
42101
+ // TODO: either both are defined or none of them. change those args to an object
42000
42102
  onGridComposerCellFocused(content, selection) {
42001
42103
  if (this.model.getters.isReadonly()) {
42002
42104
  return;
@@ -43972,12 +44074,7 @@ function addFormula(cell) {
43972
44074
  attrs.push(["t", "str"]);
43973
44075
  cycle = escapeXml /*xml*/ `<v>${cell.value}</v>`;
43974
44076
  }
43975
- node = escapeXml /*xml*/ `
43976
- <f>
43977
- ${XlsxFormula}
43978
- </f>
43979
- ${cycle}
43980
- `;
44077
+ node = escapeXml /*xml*/ `<f> ${XlsxFormula} </f> ${cycle}`;
43981
44078
  return { attrs, node };
43982
44079
  }
43983
44080
  else {
@@ -44773,11 +44870,10 @@ function addRows(construct, data, sheet) {
44773
44870
  ({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader));
44774
44871
  }
44775
44872
  attributes.push(...additionalAttrs);
44776
- cellNodes.push(escapeXml /*xml*/ `
44777
- <c ${formatAttributes(attributes)}>
44778
- ${cellNode}
44779
- </c>
44780
- `);
44873
+ // prettier-ignore
44874
+ cellNodes.push(escapeXml /*xml*/ `<c ${formatAttributes(attributes)}>
44875
+ ${cellNode}
44876
+ </c>`);
44781
44877
  }
44782
44878
  }
44783
44879
  if (cellNodes.length || row.size !== DEFAULT_CELL_HEIGHT || row.isHidden) {
@@ -45643,6 +45739,6 @@ function addFunction(functionName, functionDescription) {
45643
45739
  export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setTranslationMethod, tokenize };
45644
45740
 
45645
45741
 
45646
- __info__.version = '16.2.29';
45647
- __info__.date = '2024-01-29T13:49:36.240Z';
45648
- __info__.hash = '27b2ec1';
45742
+ __info__.version = '16.2.31';
45743
+ __info__.date = '2024-02-09T13:05:40.161Z';
45744
+ __info__.hash = '2e76bdf';