@odoo/o-spreadsheet 17.1.3 → 17.1.4

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.1.3
6
- * @date 2024-02-02T13:46:54.332Z
7
- * @hash 798f979
5
+ * @version 17.1.4
6
+ * @date 2024-02-09T13:09:13.430Z
7
+ * @hash 16d3ece
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';
@@ -2938,6 +2938,9 @@ function formatValue(value, { format, locale }) {
2938
2938
  }
2939
2939
  switch (typeof value) {
2940
2940
  case "string":
2941
+ if (value.includes('\\"')) {
2942
+ return value.replace(/\\"/g, '"');
2943
+ }
2941
2944
  return value;
2942
2945
  case "boolean":
2943
2946
  return value ? "TRUE" : "FALSE";
@@ -4991,14 +4994,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
4991
4994
  : undefined));
4992
4995
  }
4993
4996
  }
4994
- else if (zone.left === zone.right && zone.top === zone.bottom) {
4995
- // A single cell. If it's only the title, the dataset is not added.
4996
- if (!dataSetsHaveTitle) {
4997
- dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
4998
- }
4999
- }
5000
4997
  else {
5001
- /* 1 row or 1 column */
4998
+ /* 1 cell, 1 row or 1 column */
5002
4999
  dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
5003
5000
  ? {
5004
5001
  top: zone.top,
@@ -7441,7 +7438,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
7441
7438
  while (!chars.isOver()) {
7442
7439
  let token = tokenizeSpace(chars) ||
7443
7440
  tokenizeArgsSeparator(chars, locale) ||
7444
- tokenizeMisc(chars) ||
7441
+ tokenizeParenthesis(chars) ||
7445
7442
  tokenizeOperator(chars) ||
7446
7443
  tokenizeString(chars) ||
7447
7444
  tokenizeDebugger(chars) ||
@@ -7462,15 +7459,14 @@ function tokenizeDebugger(chars) {
7462
7459
  }
7463
7460
  return null;
7464
7461
  }
7465
- const misc$1 = {
7466
- "(": "LEFT_PAREN",
7467
- ")": "RIGHT_PAREN",
7462
+ const parenthesis = {
7463
+ "(": { type: "LEFT_PAREN", value: "(" },
7464
+ ")": { type: "RIGHT_PAREN", value: ")" },
7468
7465
  };
7469
- function tokenizeMisc(chars) {
7470
- if (chars.current in misc$1) {
7466
+ function tokenizeParenthesis(chars) {
7467
+ if (chars.current === "(" || chars.current === ")") {
7471
7468
  const value = chars.shift();
7472
- const type = misc$1[value];
7473
- return { type, value };
7469
+ return parenthesis[value];
7474
7470
  }
7475
7471
  return null;
7476
7472
  }
@@ -7491,7 +7487,12 @@ function tokenizeOperator(chars) {
7491
7487
  }
7492
7488
  return null;
7493
7489
  }
7490
+ const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
7494
7491
  function tokenizeNumber(chars, locale) {
7492
+ if (!FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
7493
+ chars.current !== locale.decimalSeparator) {
7494
+ return null;
7495
+ }
7495
7496
  const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
7496
7497
  if (match) {
7497
7498
  chars.advanceBy(match[0].length);
@@ -7516,7 +7517,7 @@ function tokenizeString(chars) {
7516
7517
  }
7517
7518
  return null;
7518
7519
  }
7519
- const separatorRegexp = /\w|\.|!|\$/;
7520
+ const separatorRegexp = /^[\w\.!\$]+/;
7520
7521
  /**
7521
7522
  * A "Symbol" is just basically any word-like element that can appear in a
7522
7523
  * formula, which is not a string. So:
@@ -7556,8 +7557,11 @@ function tokenizeSymbol(chars) {
7556
7557
  };
7557
7558
  }
7558
7559
  }
7559
- while (chars.current && separatorRegexp.test(chars.current)) {
7560
- result += chars.shift();
7560
+ const match = chars.remaining().match(separatorRegexp);
7561
+ if (match) {
7562
+ const value = match[0];
7563
+ result += value;
7564
+ chars.advanceBy(value.length);
7561
7565
  }
7562
7566
  if (result.length) {
7563
7567
  const value = result;
@@ -7619,7 +7623,10 @@ class TokenizingChars {
7619
7623
  return this.text.substring(this.currentIndex);
7620
7624
  }
7621
7625
  currentStartsWith(str) {
7622
- for (let j = 0; j < str.length; j++) {
7626
+ if (this.current !== str[0]) {
7627
+ return false;
7628
+ }
7629
+ for (let j = 1; j < str.length; j++) {
7623
7630
  if (this.text[this.currentIndex + j] !== str[j]) {
7624
7631
  return false;
7625
7632
  }
@@ -8651,7 +8658,7 @@ class BarChart extends AbstractChart {
8651
8658
  return undefined;
8652
8659
  const dataSets = this.dataSets
8653
8660
  .map((ds) => toExcelDataset(this.getters, ds))
8654
- .filter((ds) => ds.range !== ""); // && range !== CellErrorType.InvalidReference ? show incorrect #ref ?
8661
+ .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
8655
8662
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
8656
8663
  return {
8657
8664
  ...this.getDefinition(),
@@ -9229,7 +9236,7 @@ class LineChart extends AbstractChart {
9229
9236
  return undefined;
9230
9237
  const dataSets = this.dataSets
9231
9238
  .map((ds) => toExcelDataset(this.getters, ds))
9232
- .filter((ds) => ds.range !== ""); // && range !== CellErrorType.InvalidReference ? show incorrect #ref ?
9239
+ .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
9233
9240
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
9234
9241
  return {
9235
9242
  ...this.getDefinition(),
@@ -9535,7 +9542,7 @@ class PieChart extends AbstractChart {
9535
9542
  return undefined;
9536
9543
  const dataSets = this.dataSets
9537
9544
  .map((ds) => toExcelDataset(this.getters, ds))
9538
- .filter((ds) => ds.range !== ""); // && range !== CellErrorType.InvalidReference ? show incorrect #ref ?
9545
+ .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
9539
9546
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
9540
9547
  return {
9541
9548
  ...this.getDefinition(),
@@ -18682,6 +18689,9 @@ const HLOOKUP = {
18682
18689
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18683
18690
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18684
18691
  assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18692
+ if (searchKey && isEvaluationError(searchKey.value)) {
18693
+ return searchKey;
18694
+ }
18685
18695
  const getValueFromRange = (range, index) => range[index][0].value;
18686
18696
  const _isSorted = toBoolean(isSorted.value);
18687
18697
  const colIndex = _isSorted
@@ -18849,6 +18859,9 @@ const VLOOKUP = {
18849
18859
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18850
18860
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18851
18861
  assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18862
+ if (searchKey && isEvaluationError(searchKey.value)) {
18863
+ return searchKey;
18864
+ }
18852
18865
  const getValueFromRange = (range, index) => range[0][index].value;
18853
18866
  const _isSorted = toBoolean(isSorted.value);
18854
18867
  const rowIndex = _isSorted
@@ -18888,6 +18901,9 @@ const XLOOKUP = {
18888
18901
  assert(() => lookupDirection === "col"
18889
18902
  ? returnRange[0].length === lookupRange[0].length
18890
18903
  : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18904
+ if (searchKey && isEvaluationError(searchKey.value)) {
18905
+ return [[searchKey]];
18906
+ }
18891
18907
  const getElement = lookupDirection === "col"
18892
18908
  ? (range, index) => range[0][index].value
18893
18909
  : (range, index) => range[index][0].value;
@@ -26969,15 +26985,17 @@ class Composer extends Component {
26969
26985
  focus: {
26970
26986
  validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
26971
26987
  },
26972
- onComposerContentFocused: Function,
26973
26988
  inputStyle: { type: String, optional: true },
26974
26989
  rect: { type: Object, optional: true },
26975
26990
  delimitation: { type: Object, optional: true },
26976
- onComposerUnmounted: { type: Function, optional: true },
26991
+ onComposerCellFocused: { type: Function, optional: true },
26992
+ onComposerContentFocused: Function,
26993
+ isDefaultFocus: { type: Boolean, optional: true },
26977
26994
  };
26978
26995
  static components = { TextValueProvider, FunctionDescriptionProvider };
26979
26996
  static defaultProps = {
26980
26997
  inputStyle: "",
26998
+ isDefaultFocus: false,
26981
26999
  };
26982
27000
  composerRef = useRef("o_composer");
26983
27001
  contentHelper = new ContentEditableHelper(this.composerRef.el);
@@ -27034,7 +27052,6 @@ class Composer extends Component {
27034
27052
  F4: this.processF4Key,
27035
27053
  Tab: (ev) => this.processTabKey(ev, "right"),
27036
27054
  "Shift+Tab": (ev) => this.processTabKey(ev, "left"),
27037
- "Ctrl+ ": this.processSpaceKey,
27038
27055
  };
27039
27056
  keyCodeMapping = {
27040
27057
  NumpadDecimal: this.processNumpadDecimal,
@@ -27042,12 +27059,12 @@ class Composer extends Component {
27042
27059
  setup() {
27043
27060
  onMounted(() => {
27044
27061
  const el = this.composerRef.el;
27062
+ if (this.props.isDefaultFocus) {
27063
+ this.env.focusableElement.setFocusableElement(el);
27064
+ }
27045
27065
  this.contentHelper.updateEl(el);
27046
27066
  this.processTokenAtCursor();
27047
27067
  });
27048
- onWillUnmount(() => {
27049
- this.props.onComposerUnmounted?.();
27050
- });
27051
27068
  useEffect(() => {
27052
27069
  this.processContent();
27053
27070
  });
@@ -27056,7 +27073,8 @@ class Composer extends Component {
27056
27073
  // Handlers
27057
27074
  // ---------------------------------------------------------------------------
27058
27075
  processArrowKeys(ev) {
27059
- if (this.env.model.getters.isSelectingForComposer()) {
27076
+ if (this.env.model.getters.isSelectingForComposer() ||
27077
+ this.env.model.getters.getEditionMode() === "inactive") {
27060
27078
  this.functionDescriptionState.showDescription = false;
27061
27079
  // Prevent the default content editable behavior which moves the cursor
27062
27080
  ev.preventDefault();
@@ -27099,23 +27117,19 @@ class Composer extends Component {
27099
27117
  processTabKey(ev, direction) {
27100
27118
  ev.preventDefault();
27101
27119
  ev.stopPropagation();
27102
- const state = this.autoCompleteState;
27103
- if (state.showProvider && state.selectedIndex !== undefined) {
27104
- const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
27105
- if (autoCompleteValue) {
27106
- this.autoComplete(autoCompleteValue);
27107
- return;
27120
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
27121
+ const state = this.autoCompleteState;
27122
+ if (state.showProvider && state.selectedIndex !== undefined) {
27123
+ const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
27124
+ if (autoCompleteValue) {
27125
+ this.autoComplete(autoCompleteValue);
27126
+ return;
27127
+ }
27108
27128
  }
27129
+ interactiveStopEdition(this.env);
27109
27130
  }
27110
- interactiveStopEdition(this.env);
27111
27131
  this.env.model.selection.moveAnchorCell(direction, 1);
27112
27132
  }
27113
- processSpaceKey(ev) {
27114
- ev.preventDefault();
27115
- ev.stopPropagation();
27116
- this.showFunctionAutocomplete("");
27117
- this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
27118
- }
27119
27133
  processEnterKey(ev, direction) {
27120
27134
  ev.preventDefault();
27121
27135
  ev.stopPropagation();
@@ -27177,6 +27191,9 @@ class Composer extends Component {
27177
27191
  this.compositionActive = false;
27178
27192
  }
27179
27193
  onKeydown(ev) {
27194
+ if (this.env.model.getters.getEditionMode() === "inactive") {
27195
+ return;
27196
+ }
27180
27197
  if (ev.key.startsWith("Arrow")) {
27181
27198
  this.processArrowKeys(ev);
27182
27199
  return;
@@ -27190,14 +27207,33 @@ class Composer extends Component {
27190
27207
  ev.stopPropagation();
27191
27208
  }
27192
27209
  }
27210
+ onPaste(ev) {
27211
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
27212
+ ev.stopPropagation();
27213
+ }
27214
+ }
27193
27215
  /*
27194
27216
  * Triggered automatically by the content-editable between the keydown and key up
27195
27217
  * */
27196
27218
  onInput(ev) {
27197
- if (this.props.focus === "inactive" || !this.shouldProcessInputEvents) {
27219
+ if (!this.shouldProcessInputEvents) {
27220
+ return;
27221
+ }
27222
+ if (ev.inputType === "insertFromPaste" &&
27223
+ this.env.model.getters.getEditionMode() === "inactive") {
27198
27224
  return;
27199
27225
  }
27200
- let content = this.contentHelper.getText();
27226
+ ev.stopPropagation();
27227
+ let content;
27228
+ if (this.env.model.getters.getEditionMode() === "inactive") {
27229
+ content = ev.data || "";
27230
+ }
27231
+ else {
27232
+ content = this.contentHelper.getText();
27233
+ }
27234
+ if (this.props.focus === "inactive") {
27235
+ return this.props.onComposerCellFocused?.(content);
27236
+ }
27201
27237
  let selection = this.contentHelper.getCurrentSelection();
27202
27238
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
27203
27239
  this.env.model.dispatch("SET_CURRENT_CONTENT", {
@@ -27273,9 +27309,8 @@ class Composer extends Component {
27273
27309
  }
27274
27310
  const newSelection = this.contentHelper.getCurrentSelection();
27275
27311
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
27276
- if (this.props.focus === "inactive") {
27277
- this.props.onComposerContentFocused(newSelection);
27278
- }
27312
+ this.props.onComposerContentFocused();
27313
+ if (this.props.focus === "inactive") ;
27279
27314
  this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
27280
27315
  this.processTokenAtCursor();
27281
27316
  }
@@ -27442,7 +27477,7 @@ class Composer extends Component {
27442
27477
  const highlights = this.env.model.getters.getHighlights();
27443
27478
  const refSheet = sheetName
27444
27479
  ? this.env.model.getters.getSheetIdByName(sheetName)
27445
- : this.env.model.getters.getCurrentEditedCell().sheetId;
27480
+ : this.env.model.getters.getCurrentEditedCell()?.sheetId;
27446
27481
  const highlight = highlights.find((highlight) => {
27447
27482
  if (highlight.sheetId !== refSheet)
27448
27483
  return false;
@@ -27569,56 +27604,30 @@ class GridComposer extends Component {
27569
27604
  focus: {
27570
27605
  validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
27571
27606
  },
27572
- onComposerUnmounted: Function,
27607
+ onComposerCellFocused: Function,
27573
27608
  onComposerContentFocused: Function,
27574
27609
  gridDims: Object,
27575
27610
  };
27576
27611
  static components = { Composer };
27577
- gridComposerRef;
27578
- zone;
27579
- rect;
27612
+ rect = this.defaultRect;
27613
+ isEditing = false;
27580
27614
  isCellReferenceVisible;
27581
- composerState;
27615
+ get defaultRect() {
27616
+ return { x: 0, y: 0, width: 0, height: 0 };
27617
+ }
27582
27618
  setup() {
27583
- this.gridComposerRef = useRef("gridComposer");
27584
- this.composerState = useState({
27585
- rect: undefined,
27586
- delimitation: undefined,
27587
- });
27588
- const { sheetId, col, row } = this.env.model.getters.getActivePosition();
27589
- this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
27590
- this.rect = this.env.model.getters.getVisibleRect(this.zone);
27591
- this.isCellReferenceVisible = false;
27592
- onMounted(() => {
27593
- const el = this.gridComposerRef.el;
27594
- this.composerState.rect = {
27595
- x: this.rect.x,
27596
- y: this.rect.y,
27597
- width: el.clientWidth,
27598
- height: el.clientHeight,
27599
- };
27600
- this.composerState.delimitation = {
27601
- width: this.props.gridDims.width,
27602
- height: this.props.gridDims.height,
27603
- };
27604
- });
27605
27619
  onWillUpdateProps(() => {
27606
- if (this.isCellReferenceVisible) {
27607
- return;
27608
- }
27609
- const sheetId = this.env.model.getters.getActiveSheetId();
27610
- const zone = this.env.model.getters.getSelectedZone();
27611
- const rect = this.env.model.getters.getVisibleRect(zone);
27612
- if (!deepEquals(rect, this.rect) ||
27613
- sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
27614
- this.isCellReferenceVisible = true;
27615
- }
27620
+ this.updateComponentPosition();
27621
+ this.updateCellReferenceVisibility();
27616
27622
  });
27617
27623
  }
27618
27624
  get shouldDisplayCellReference() {
27619
27625
  return this.isCellReferenceVisible;
27620
27626
  }
27621
27627
  get cellReference() {
27628
+ if (!this.env.model.getters.getCurrentEditedCell()) {
27629
+ return "";
27630
+ }
27622
27631
  const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
27623
27632
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
27624
27633
  return getFullReference(prefixSheet ? this.env.model.getters.getSheetName(sheetId) : undefined, toXC(col, row));
@@ -27630,7 +27639,27 @@ class GridComposer extends Component {
27630
27639
  top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
27631
27640
  });
27632
27641
  }
27642
+ get composerProps() {
27643
+ const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
27644
+ return {
27645
+ rect: { ...this.rect },
27646
+ delimitation: {
27647
+ width,
27648
+ height,
27649
+ },
27650
+ focus: this.props.focus,
27651
+ isDefaultFocus: true,
27652
+ onComposerContentFocused: this.props.onComposerContentFocused,
27653
+ onComposerCellFocused: this.props.onComposerCellFocused,
27654
+ };
27655
+ }
27633
27656
  get containerStyle() {
27657
+ if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27658
+ return `
27659
+ position: absolute;
27660
+ z-index: -1000;
27661
+ `;
27662
+ }
27634
27663
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27635
27664
  const cell = this.env.model.getters.getActiveCell();
27636
27665
  const position = this.env.model.getters.getActivePosition();
@@ -27650,6 +27679,8 @@ class GridComposer extends Component {
27650
27679
  if (!isFormula) {
27651
27680
  textAlign = style.align || cell.defaultAlign;
27652
27681
  }
27682
+ const maxHeight = this.props.gridDims.height - this.rect.y;
27683
+ const maxWidth = this.props.gridDims.width - this.rect.x;
27653
27684
  /**
27654
27685
  * min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
27655
27686
  * including all the paddings/margins of the composer
@@ -27661,6 +27692,8 @@ class GridComposer extends Component {
27661
27692
  top: `${top}px`,
27662
27693
  "min-width": `${width + 1}px`,
27663
27694
  "min-height": `${height + 1}px`,
27695
+ "max-width": `${maxWidth}px`,
27696
+ "max-height": `${maxHeight}px`,
27664
27697
  background,
27665
27698
  color,
27666
27699
  "font-size": `${fontSizeInPixels(fontSize)}px`,
@@ -27670,13 +27703,31 @@ class GridComposer extends Component {
27670
27703
  "text-align": textAlign,
27671
27704
  });
27672
27705
  }
27673
- get composerStyle() {
27674
- const maxHeight = this.props.gridDims.height - this.rect.y;
27675
- const maxWidth = this.props.gridDims.width - this.rect.x;
27676
- return cssPropertiesToCss({
27677
- "max-width": `${maxWidth}px`,
27678
- "max-height": `${maxHeight}px`,
27679
- });
27706
+ updateComponentPosition() {
27707
+ const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
27708
+ if (this.isEditing !== isEditing) {
27709
+ this.isEditing = isEditing;
27710
+ if (!isEditing) {
27711
+ this.rect = this.defaultRect;
27712
+ this.env.focusableElement.focus();
27713
+ return;
27714
+ }
27715
+ const position = this.env.model.getters.getActivePosition();
27716
+ const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
27717
+ this.rect = this.env.model.getters.getVisibleRect(zone);
27718
+ }
27719
+ }
27720
+ updateCellReferenceVisibility() {
27721
+ if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
27722
+ return;
27723
+ }
27724
+ const sheetId = this.env.model.getters.getActiveSheetId();
27725
+ const zone = this.env.model.getters.getSelectedZone();
27726
+ const rect = this.env.model.getters.getVisibleRect(zone);
27727
+ if (!deepEquals(rect, this.rect) ||
27728
+ sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
27729
+ this.isCellReferenceVisible = true;
27730
+ }
27680
27731
  }
27681
27732
  }
27682
27733
 
@@ -28776,7 +28827,6 @@ class GridOverlay extends Component {
28776
28827
  this.props.onCellDoubleClicked(col, row);
28777
28828
  }
28778
28829
  onContextMenu(ev) {
28779
- ev.preventDefault();
28780
28830
  const [col, row] = this.getCartesianCoordinates(ev);
28781
28831
  this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
28782
28832
  }
@@ -29841,7 +29891,6 @@ class Grid extends Component {
29841
29891
  HEADER_WIDTH = HEADER_WIDTH;
29842
29892
  menuState;
29843
29893
  gridRef;
29844
- hiddenInput;
29845
29894
  onMouseWheel;
29846
29895
  canvasPosition;
29847
29896
  hoveredCell;
@@ -29852,15 +29901,14 @@ class Grid extends Component {
29852
29901
  menuItems: [],
29853
29902
  });
29854
29903
  this.gridRef = useRef("grid");
29855
- this.hiddenInput = useRef("hiddenInput");
29856
29904
  this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
29857
29905
  this.hoveredCell = useState({ col: undefined, row: undefined });
29858
29906
  useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
29859
29907
  useExternalListener(document.body, "cut", this.copy.bind(this, true));
29860
29908
  useExternalListener(document.body, "copy", this.copy.bind(this, false));
29861
29909
  useExternalListener(document.body, "paste", this.paste);
29862
- onMounted(() => this.focus());
29863
- this.props.exposeFocus(() => this.focus());
29910
+ onMounted(() => this.focusDefaultElement());
29911
+ this.props.exposeFocus(() => this.focusDefaultElement());
29864
29912
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
29865
29913
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
29866
29914
  this.moveCanvas(deltaX, deltaY);
@@ -29884,7 +29932,7 @@ class Grid extends Component {
29884
29932
  if (this.env.model.getters.hasOpenedPopover()) {
29885
29933
  this.closeOpenedPopover();
29886
29934
  }
29887
- this.focus();
29935
+ this.focusDefaultElement();
29888
29936
  }
29889
29937
  // this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
29890
29938
  // down itself
@@ -30063,10 +30111,10 @@ class Grid extends Component {
30063
30111
  "Alt+Shift+ArrowUp": () => this.processHeaderGroupingKey("up"),
30064
30112
  "Alt+Shift+ArrowDown": () => this.processHeaderGroupingKey("down"),
30065
30113
  };
30066
- focus() {
30114
+ focusDefaultElement() {
30067
30115
  if (!this.env.model.getters.getSelectedFigureId() &&
30068
30116
  this.env.model.getters.getEditionMode() === "inactive") {
30069
- this.hiddenInput.el?.focus();
30117
+ this.env.focusableElement.focus();
30070
30118
  }
30071
30119
  }
30072
30120
  get gridEl() {
@@ -30202,19 +30250,6 @@ class Grid extends Component {
30202
30250
  return;
30203
30251
  }
30204
30252
  }
30205
- onInput(ev) {
30206
- // the user meant to paste in the sheet, not open the composer with the pasted content
30207
- if (!ev.isComposing && ev.inputType === "insertFromPaste") {
30208
- return;
30209
- }
30210
- if (ev.data) {
30211
- // if the user types a character on the grid, it means he wants to start composing the selected cell with that
30212
- // character
30213
- ev.preventDefault();
30214
- ev.stopPropagation();
30215
- this.props.onGridComposerCellFocused(ev.data);
30216
- }
30217
- }
30218
30253
  // ---------------------------------------------------------------------------
30219
30254
  // Context Menu
30220
30255
  // ---------------------------------------------------------------------------
@@ -30329,7 +30364,7 @@ class Grid extends Component {
30329
30364
  }
30330
30365
  closeMenu() {
30331
30366
  this.menuState.isOpen = false;
30332
- this.focus();
30367
+ this.focusDefaultElement();
30333
30368
  }
30334
30369
  processHeaderGroupingKey(direction) {
30335
30370
  if (this.env.model.getters.getSelectedZones().length !== 1) {
@@ -34246,6 +34281,31 @@ const MIGRATIONS = [
34246
34281
  return data;
34247
34282
  },
34248
34283
  },
34284
+ {
34285
+ description: "Fix datafilter duplication",
34286
+ from: 12,
34287
+ to: 12.5,
34288
+ applyMigration(data) {
34289
+ for (let sheet of data.sheets || []) {
34290
+ let knownDataFilterZones = [];
34291
+ for (let filterTable of sheet.filterTables || []) {
34292
+ const zone = toZone(filterTable.range);
34293
+ // See commit message for the details
34294
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34295
+ if (intersectZoneIndex !== -1) {
34296
+ knownDataFilterZones[intersectZoneIndex] = zone;
34297
+ }
34298
+ else {
34299
+ knownDataFilterZones.push(zone);
34300
+ }
34301
+ }
34302
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
34303
+ range: zoneToXc(zone),
34304
+ }));
34305
+ }
34306
+ return data;
34307
+ },
34308
+ },
34249
34309
  {
34250
34310
  description: "Change Border description structure",
34251
34311
  from: 12,
@@ -36032,9 +36092,6 @@ class CellPlugin extends CorePlugin {
36032
36092
  format: cell.format ? getItemId(cell.format, formats) : undefined,
36033
36093
  content: cell.content || undefined,
36034
36094
  };
36035
- if (cell instanceof FormulaCellWithDependencies) {
36036
- cells[xc].content = cell.contentWithFixedReferences || undefined;
36037
- }
36038
36095
  }
36039
36096
  _sheet.cells = cells;
36040
36097
  }
@@ -36286,8 +36343,11 @@ class CellPlugin extends CorePlugin {
36286
36343
  * being a computed property to rebuild the dependencies XC.
36287
36344
  */
36288
36345
  createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
36289
- const dependencies = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
36290
- return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString.bind(this));
36346
+ const dependencies = [];
36347
+ for (const xc of compiledFormula.dependencies) {
36348
+ dependencies.push(this.getters.getRangeFromSheetXC(sheetId, xc));
36349
+ }
36350
+ return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString);
36291
36351
  }
36292
36352
  createErrorFormula(id, content, format, style, error) {
36293
36353
  return {
@@ -36341,7 +36401,7 @@ class FormulaCellWithDependencies {
36341
36401
  const tokens = compiledFormula.tokens.map((token) => {
36342
36402
  if (token.type === "REFERENCE") {
36343
36403
  const index = rangeIndex++;
36344
- return new RangeReferenceToken(() => this.getRangeString(dependencies[index], this.sheetId));
36404
+ return new RangeReferenceToken(dependencies, index, this.sheetId, this.getRangeString);
36345
36405
  }
36346
36406
  return token;
36347
36407
  });
@@ -36368,13 +36428,20 @@ class FormulaCellWithDependencies {
36368
36428
  }
36369
36429
  }
36370
36430
  class RangeReferenceToken {
36371
- getValue;
36431
+ ranges;
36432
+ rangeIndex;
36433
+ sheetId;
36434
+ getRangeString;
36372
36435
  type = "REFERENCE";
36373
- constructor(getValue) {
36374
- this.getValue = getValue;
36436
+ constructor(ranges, rangeIndex, sheetId, getRangeString) {
36437
+ this.ranges = ranges;
36438
+ this.rangeIndex = rangeIndex;
36439
+ this.sheetId = sheetId;
36440
+ this.getRangeString = getRangeString;
36375
36441
  }
36376
36442
  get value() {
36377
- return this.getValue();
36443
+ const range = this.ranges[this.rangeIndex];
36444
+ return this.getRangeString(range, this.sheetId);
36378
36445
  }
36379
36446
  }
36380
36447
 
@@ -41909,7 +41976,13 @@ class EvaluationPlugin extends UIPlugin {
41909
41976
  const format = newFormat
41910
41977
  ? getItemId(newFormat, data.formats)
41911
41978
  : exportedCellData.format;
41912
- const content = !isExported ? newContent : exportedCellData.content;
41979
+ let content;
41980
+ if (formulaCell instanceof FormulaCellWithDependencies) {
41981
+ content = formulaCell.contentWithFixedReferences;
41982
+ }
41983
+ else {
41984
+ content = !isExported ? newContent : exportedCellData.content;
41985
+ }
41913
41986
  exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
41914
41987
  }
41915
41988
  }
@@ -51093,6 +51166,16 @@ class ImageProvider {
51093
51166
  }
51094
51167
  }
51095
51168
 
51169
+ class FocusableElement {
51170
+ focusableElement = undefined;
51171
+ setFocusableElement(element) {
51172
+ this.focusableElement = element;
51173
+ }
51174
+ focus() {
51175
+ this.focusableElement?.focus();
51176
+ }
51177
+ }
51178
+
51096
51179
  const RIPPLE_KEY_FRAMES = [
51097
51180
  { transform: "scale(0)" },
51098
51181
  { transform: "scale(0.8)", offset: 0.33 },
@@ -53247,6 +53330,7 @@ class Spreadsheet extends Component {
53247
53330
  toggleSidePanel: this.toggleSidePanel.bind(this),
53248
53331
  clipboard: this.env.clipboard || instantiateClipboard(),
53249
53332
  startCellEdition: (content) => this.onGridComposerCellFocused(content),
53333
+ focusableElement: new FocusableElement(),
53250
53334
  });
53251
53335
  useEffect(() => {
53252
53336
  /**
@@ -53365,16 +53449,17 @@ class Spreadsheet extends Component {
53365
53449
  }
53366
53450
  this.composer.topBarFocus = "contentFocus";
53367
53451
  this.composer.gridFocusMode = "inactive";
53368
- this.setComposerContent({ selection } || {});
53452
+ this.setComposerContent({ selection });
53369
53453
  }
53370
- onGridComposerContentFocused() {
53454
+ onGridComposerContentFocused(selection) {
53371
53455
  if (this.model.getters.isReadonly()) {
53372
53456
  return;
53373
53457
  }
53374
53458
  this.composer.topBarFocus = "inactive";
53375
53459
  this.composer.gridFocusMode = "contentFocus";
53376
- this.setComposerContent({});
53460
+ this.setComposerContent({ selection });
53377
53461
  }
53462
+ // TODO: either both are defined or none of them. change those args to an object
53378
53463
  onGridComposerCellFocused(content, selection) {
53379
53464
  if (this.model.getters.isReadonly()) {
53380
53465
  return;
@@ -57062,6 +57147,6 @@ const constants = {
57062
57147
  export { AbstractChart, CellErrorType, 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 };
57063
57148
 
57064
57149
 
57065
- __info__.version = "17.1.3";
57066
- __info__.date = "2024-02-02T13:46:54.332Z";
57067
- __info__.hash = "798f979";
57150
+ __info__.version = "17.1.4";
57151
+ __info__.date = "2024-02-09T13:09:13.430Z";
57152
+ __info__.hash = "16d3ece";