@odoo/o-spreadsheet 18.0.8 → 18.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.0.8
6
- * @date 2024-12-19T07:50:36.150Z
7
- * @hash 7cf34a6
5
+ * @version 18.0.10
6
+ * @date 2025-01-15T08:05:47.616Z
7
+ * @hash 94c45c7
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -3540,6 +3540,7 @@ var CommandResult;
3540
3540
  CommandResult["SheetIsHidden"] = "SheetIsHidden";
3541
3541
  CommandResult["InvalidTableResize"] = "InvalidTableResize";
3542
3542
  CommandResult["PivotIdNotFound"] = "PivotIdNotFound";
3543
+ CommandResult["PivotInError"] = "PivotInError";
3543
3544
  CommandResult["EmptyName"] = "EmptyName";
3544
3545
  CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
3545
3546
  CommandResult["InvalidDefinition"] = "InvalidDefinition";
@@ -9386,9 +9387,9 @@ function getTrendDatasetForBarChart(config, dataset) {
9386
9387
  if (!newValues.length) {
9387
9388
  return;
9388
9389
  }
9389
- return getFullTrendingLineDataSet(dataset, config, newValues);
9390
+ return getFullTrendingLineDataSet(dataset, config, newValues, newLabels);
9390
9391
  }
9391
- function getFullTrendingLineDataSet(dataset, config, data) {
9392
+ function getFullTrendingLineDataSet(dataset, config, data, labels) {
9392
9393
  const defaultBorderColor = colorToRGBA(dataset.backgroundColor);
9393
9394
  defaultBorderColor.a = 1;
9394
9395
  const borderColor = config.color || lightenColor(rgbaToHex(defaultBorderColor), 0.5);
@@ -9397,7 +9398,7 @@ function getFullTrendingLineDataSet(dataset, config, data) {
9397
9398
  xAxisID: TREND_LINE_XAXIS_ID,
9398
9399
  yAxisID: dataset.yAxisID,
9399
9400
  label: dataset.label ? _t("Trend line for %s", dataset.label) : "",
9400
- data,
9401
+ data: data.map((v, i) => ({ x: labels[i], y: v })),
9401
9402
  order: -1,
9402
9403
  showLine: true,
9403
9404
  pointRadius: 0,
@@ -19568,6 +19569,17 @@ const TEXT = {
19568
19569
  },
19569
19570
  isExported: true,
19570
19571
  };
19572
+ // -----------------------------------------------------------------------------
19573
+ // VALUE
19574
+ // -----------------------------------------------------------------------------
19575
+ const VALUE = {
19576
+ description: _t("Converts a string to a numeric value."),
19577
+ args: [arg("value (number)", _t("the string to be converted"))],
19578
+ compute: function (value) {
19579
+ return toNumber(value, this.locale);
19580
+ },
19581
+ isExported: true,
19582
+ };
19571
19583
 
19572
19584
  var text = /*#__PURE__*/Object.freeze({
19573
19585
  __proto__: null,
@@ -19590,7 +19602,8 @@ var text = /*#__PURE__*/Object.freeze({
19590
19602
  TEXT: TEXT,
19591
19603
  TEXTJOIN: TEXTJOIN,
19592
19604
  TRIM: TRIM,
19593
- UPPER: UPPER
19605
+ UPPER: UPPER,
19606
+ VALUE: VALUE
19594
19607
  });
19595
19608
 
19596
19609
  // -----------------------------------------------------------------------------
@@ -19854,14 +19867,11 @@ autoCompleteProviders.add("functions", {
19854
19867
  });
19855
19868
 
19856
19869
  class DOMFocusableElementStore {
19857
- mutators = ["setFocusableElement", "focus"];
19870
+ mutators = ["setFocusableElement"];
19858
19871
  focusableElement = undefined;
19859
19872
  setFocusableElement(element) {
19860
19873
  this.focusableElement = element;
19861
19874
  }
19862
- focus() {
19863
- this.focusableElement?.focus();
19864
- }
19865
19875
  }
19866
19876
 
19867
19877
  /**
@@ -20826,7 +20836,7 @@ class Composer extends Component {
20826
20836
  if (document.activeElement === this.contentHelper.el &&
20827
20837
  this.props.composerStore.editionMode === "inactive" &&
20828
20838
  !this.props.isDefaultFocus) {
20829
- this.DOMFocusableElementStore.focus();
20839
+ this.DOMFocusableElementStore.focusableElement?.focus();
20830
20840
  }
20831
20841
  });
20832
20842
  useEffect(() => {
@@ -24410,7 +24420,7 @@ function extractStyle(cell, data) {
24410
24420
  vertical: style.verticalAlign
24411
24421
  ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
24412
24422
  : undefined,
24413
- wrapText: style.wrapping === "wrap" || undefined,
24423
+ wrapText: style.wrapping === "wrap" || cell.content?.includes(NEWLINE) ? true : undefined,
24414
24424
  },
24415
24425
  };
24416
24426
  styles.font["strike"] = !!style?.strikethrough || undefined;
@@ -24633,7 +24643,7 @@ function convertFigure(figure, id, sheetData) {
24633
24643
  return undefined;
24634
24644
  }
24635
24645
  function isChartData(data) {
24636
- return "dataSets" in data;
24646
+ return "dataSets" in data && data.dataSets.length > 0;
24637
24647
  }
24638
24648
  function isImageData(data) {
24639
24649
  return "imageSrc" in data;
@@ -24872,9 +24882,8 @@ function convertRows(sheet, numberOfRows, headerGroups) {
24872
24882
  }
24873
24883
  return rows;
24874
24884
  }
24875
- /** Remove newlines (\n) in shared strings, We do not support them */
24876
24885
  function convertSharedStrings(xlsxSharedStrings) {
24877
- return xlsxSharedStrings.map((str) => str.replace(/\n/g, ""));
24886
+ return xlsxSharedStrings.map(replaceNewLines);
24878
24887
  }
24879
24888
  function convertCells(sheet, data, sheetDims, warningManager) {
24880
24889
  const cells = {};
@@ -25975,15 +25984,10 @@ class XlsxMiscExtractor extends XlsxBaseExtractor {
25975
25984
  getSharedStrings() {
25976
25985
  return this.mapOnElements({ parent: this.rootFile.file.xml, query: "si" }, (ssElement) => {
25977
25986
  // Shared string can either be a simple text, or a rich text (text with formatting, possibly in multiple parts)
25978
- if (ssElement.children[0].tagName === "t") {
25979
- return this.extractTextContent(ssElement) || "";
25980
- }
25981
25987
  // We don't support rich text formatting, we'll only extract the text
25982
- else {
25983
- return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
25984
- return this.extractTextContent(textElement) || "";
25985
- }).join("");
25986
- }
25988
+ return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
25989
+ return this.extractTextContent(textElement) || "";
25990
+ }).join("");
25987
25991
  });
25988
25992
  }
25989
25993
  }
@@ -28336,7 +28340,7 @@ function getChartDatasetValues(getters, dataSets) {
28336
28340
  // then using the classical aggregation method to sum the values.
28337
28341
  data.fill(1);
28338
28342
  }
28339
- else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), getters.getLocale()))) {
28343
+ else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), DEFAULT_LOCALE))) {
28340
28344
  continue;
28341
28345
  }
28342
28346
  datasetValues.push({ data, label });
@@ -28912,12 +28916,12 @@ function getTrendDatasetForLineChart(config, dataset, axisType, locale) {
28912
28916
  }
28913
28917
  const numberOfStep = 5 * labels.length;
28914
28918
  const step = (xmax - xmin) / numberOfStep;
28915
- const newLabels = range(xmin, xmax + step / 2, step);
28916
- const newValues = interpolateData(config, filteredValues, filteredLabels, newLabels);
28917
- if (!newValues.length) {
28919
+ const trendLabels = range(xmin, xmax + step / 2, step);
28920
+ const trendValues = interpolateData(config, filteredValues, filteredLabels, trendLabels);
28921
+ if (!trendValues.length) {
28918
28922
  return;
28919
28923
  }
28920
- return getFullTrendingLineDataSet(dataset, config, newValues);
28924
+ return getFullTrendingLineDataSet(dataset, config, trendValues, trendLabels);
28921
28925
  }
28922
28926
  function createLineOrScatterChartRuntime(chart, getters) {
28923
28927
  const axisType = getChartAxisType(chart, getters);
@@ -29034,8 +29038,16 @@ function createLineOrScatterChartRuntime(chart, getters) {
29034
29038
  config.options.scales.x.type = "linear";
29035
29039
  config.options.scales.x.ticks.callback = (value) => formatValue(value, { format: labelFormat, locale });
29036
29040
  config.options.plugins.tooltip.callbacks.label = (tooltipItem) => {
29037
- const dataSetPoint = dataSetsValues[tooltipItem.datasetIndex].data[tooltipItem.dataIndex];
29038
- let label = tooltipItem.label || labelValues.values[tooltipItem.dataIndex];
29041
+ let dataSetPoint;
29042
+ let label;
29043
+ if (tooltipItem.dataset.xAxisID === TREND_LINE_XAXIS_ID) {
29044
+ dataSetPoint = dataSetsValues[tooltipItem.datasetIndex].data[tooltipItem.dataIndex].y;
29045
+ label = "";
29046
+ }
29047
+ else {
29048
+ dataSetPoint = dataSetsValues[tooltipItem.datasetIndex].data[tooltipItem.dataIndex];
29049
+ label = labelValues.values[tooltipItem.dataIndex];
29050
+ }
29039
29051
  if (isNumber(label, locale)) {
29040
29052
  label = toNumber(label, locale);
29041
29053
  }
@@ -29106,16 +29118,18 @@ function createLineOrScatterChartRuntime(chart, getters) {
29106
29118
  }
29107
29119
  }
29108
29120
  if (trendDatasets.length) {
29109
- /* We add a second x axis here to draw the trend lines, with the labels length being
29110
- * set so that the second axis points match the classical x axis
29111
- */
29112
29121
  config.options.scales[TREND_LINE_XAXIS_ID] = {
29113
29122
  ...xAxis,
29114
- type: "category",
29115
- labels: range(0, maxLength).map((x) => x.toString()),
29116
- offset: false,
29117
29123
  display: false,
29118
29124
  };
29125
+ if (axisType === "category" || axisType === "time") {
29126
+ /* We add a second x axis here to draw the trend lines, with the labels length being
29127
+ * set so that the second axis points match the classical x axis
29128
+ */
29129
+ config.options.scales[TREND_LINE_XAXIS_ID]["type"] = "category";
29130
+ config.options.scales[TREND_LINE_XAXIS_ID]["labels"] = range(0, maxLength).map((x) => x.toString());
29131
+ config.options.scales[TREND_LINE_XAXIS_ID]["offset"] = false;
29132
+ }
29119
29133
  /* These datasets must be inserted after the original datasets to ensure the way we
29120
29134
  * distinguish the originals and trendLine datasets after
29121
29135
  */
@@ -29606,7 +29620,11 @@ function createGaugeChartRuntime(chart, getters) {
29606
29620
  colors.push(chartColors.upperColor);
29607
29621
  return {
29608
29622
  background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
29609
- title: chart.title ?? { text: "" },
29623
+ title: {
29624
+ ...chart.title,
29625
+ // chart titles are extracted from .json files and they are translated at runtime here
29626
+ text: _t(chart.title.text ?? ""),
29627
+ },
29610
29628
  minValue: {
29611
29629
  value: minValue,
29612
29630
  label: formatValue(minValue, { locale, format }),
@@ -34287,12 +34305,20 @@ function fontSizeMenuBuilder() {
34287
34305
  });
34288
34306
  }
34289
34307
  function isAutomaticFormatSelected(env) {
34290
- const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
34291
- return !activeCell || !activeCell.format;
34308
+ const activePosition = env.model.getters.getActivePosition();
34309
+ const pivotCell = env.model.getters.getPivotCellFromPosition(activePosition);
34310
+ if (pivotCell.type === "VALUE") {
34311
+ return !env.model.getters.getEvaluatedCell(activePosition).format;
34312
+ }
34313
+ return !env.model.getters.getCell(activePosition)?.format;
34292
34314
  }
34293
34315
  function isFormatSelected(env, format) {
34294
- const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
34295
- return activeCell?.format === format;
34316
+ const activePosition = env.model.getters.getActivePosition();
34317
+ const pivotCell = env.model.getters.getPivotCellFromPosition(activePosition);
34318
+ if (pivotCell.type === "VALUE") {
34319
+ return env.model.getters.getEvaluatedCell(activePosition).format === format;
34320
+ }
34321
+ return env.model.getters.getCell(activePosition)?.format === format;
34296
34322
  }
34297
34323
  function isFontSizeSelected(env, fontSize) {
34298
34324
  const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
@@ -39975,6 +40001,10 @@ css /* scss */ `
39975
40001
  border: 1px solid #d8dadd;
39976
40002
  color: #374151;
39977
40003
  }
40004
+
40005
+ table {
40006
+ table-layout: fixed;
40007
+ }
39978
40008
  }
39979
40009
  `;
39980
40010
  class CustomCurrencyPanel extends Component {
@@ -42210,16 +42240,21 @@ class TextInput extends Component {
42210
42240
  }
42211
42241
  this.inputRef.el?.blur();
42212
42242
  }
42213
- focusInputAndSelectContent() {
42214
- const inputEl = this.inputRef.el;
42215
- if (!inputEl)
42216
- return;
42217
- // The onFocus event selects all text in the input.
42218
- // The subsequent mouseup event can deselect this text,
42219
- // so t-on-mouseup.prevent.stop is used to prevent this
42220
- // default behavior and preserve the selection.
42221
- inputEl.focus();
42222
- inputEl.select();
42243
+ onMouseDown(ev) {
42244
+ // Stop the event if the input is not focused, we handle everything in onMouseUp
42245
+ if (ev.target !== document.activeElement) {
42246
+ ev.preventDefault();
42247
+ ev.stopPropagation();
42248
+ }
42249
+ }
42250
+ onMouseUp(ev) {
42251
+ const target = ev.target;
42252
+ if (target !== document.activeElement) {
42253
+ target.focus();
42254
+ target.select();
42255
+ ev.preventDefault();
42256
+ ev.stopPropagation();
42257
+ }
42223
42258
  }
42224
42259
  }
42225
42260
 
@@ -42697,7 +42732,16 @@ class PivotTitleSection extends Component {
42697
42732
  newPivotId,
42698
42733
  newSheetId,
42699
42734
  });
42700
- const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
42735
+ let text;
42736
+ if (result.isSuccessful) {
42737
+ text = _t("Pivot duplicated.");
42738
+ }
42739
+ else if (result.isCancelledBecause("PivotInError" /* CommandResult.PivotInError */)) {
42740
+ text = _t("Cannot duplicate a pivot in error.");
42741
+ }
42742
+ else {
42743
+ text = _t("Pivot duplication failed.");
42744
+ }
42701
42745
  const type = result.isSuccessful ? "success" : "danger";
42702
42746
  this.env.notifyUser({
42703
42747
  text,
@@ -43995,7 +44039,9 @@ class PivotSidePanelStore extends SpreadsheetStore {
43995
44039
  pivot: this.draft,
43996
44040
  });
43997
44041
  this.draft = null;
43998
- if (!this.alreadyNotified && !this.isDynamicPivotInViewport()) {
44042
+ if (!this.alreadyNotified &&
44043
+ !this.isDynamicPivotInViewport() &&
44044
+ this.isStaticPivotInViewport()) {
43999
44045
  const formulaId = this.getters.getPivotFormulaId(this.pivotId);
44000
44046
  const pivotExample = `=PIVOT(${formulaId})`;
44001
44047
  this.alreadyNotified = true;
@@ -44062,6 +44108,18 @@ class PivotSidePanelStore extends SpreadsheetStore {
44062
44108
  }
44063
44109
  return false;
44064
44110
  }
44111
+ isStaticPivotInViewport() {
44112
+ for (const position of this.getters.getVisibleCellPositions()) {
44113
+ const cell = this.getters.getCell(position);
44114
+ if (cell?.isFormula) {
44115
+ const pivotFunction = getFirstPivotFunction(cell.compiledFormula.tokens);
44116
+ if (pivotFunction && pivotFunction.functionName !== "PIVOT") {
44117
+ return true;
44118
+ }
44119
+ }
44120
+ }
44121
+ return false;
44122
+ }
44065
44123
  addDefaultDateTimeGranularity(fields, definition) {
44066
44124
  const { columns, rows } = definition;
44067
44125
  const columnsWithGranularity = deepCopy(columns);
@@ -49448,7 +49506,7 @@ class Grid extends Component {
49448
49506
  this.cellPopovers = useStore(CellPopoverStore);
49449
49507
  useEffect(() => {
49450
49508
  if (!this.sidePanel.isOpen) {
49451
- this.DOMFocusableElementStore.focus();
49509
+ this.DOMFocusableElementStore.focusableElement?.focus();
49452
49510
  }
49453
49511
  }, () => [this.sidePanel.isOpen]);
49454
49512
  }
@@ -49652,7 +49710,7 @@ class Grid extends Component {
49652
49710
  focusDefaultElement() {
49653
49711
  if (!this.env.model.getters.getSelectedFigureId() &&
49654
49712
  this.composerFocusStore.activeComposer.editionMode === "inactive") {
49655
- this.DOMFocusableElementStore.focus();
49713
+ this.DOMFocusableElementStore.focusableElement?.focus();
49656
49714
  }
49657
49715
  }
49658
49716
  get gridEl() {
@@ -50216,10 +50274,34 @@ class BordersPlugin extends CorePlugin {
50216
50274
  const elements = [...cmd.elements].sort((a, b) => b - a);
50217
50275
  for (const group of groupConsecutive(elements)) {
50218
50276
  if (cmd.dimension === "COL") {
50219
- this.shiftBordersHorizontally(cmd.sheetId, group[group.length - 1] + 1, -group.length);
50277
+ if (group[0] >= this.getters.getNumberCols(cmd.sheetId)) {
50278
+ for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
50279
+ this.history.update("borders", cmd.sheetId, group[0] + 1, row, "vertical", undefined);
50280
+ }
50281
+ }
50282
+ if (group[group.length - 1] === 0) {
50283
+ for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
50284
+ this.history.update("borders", cmd.sheetId, 0, row, "vertical", undefined);
50285
+ }
50286
+ }
50287
+ const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
50288
+ this.clearInsideBorders(cmd.sheetId, [zone]);
50289
+ this.shiftBordersHorizontally(cmd.sheetId, group[0] + 1, -group.length);
50220
50290
  }
50221
50291
  else {
50222
- this.shiftBordersVertically(cmd.sheetId, group[group.length - 1] + 1, -group.length);
50292
+ if (group[0] >= this.getters.getNumberRows(cmd.sheetId)) {
50293
+ for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
50294
+ this.history.update("borders", cmd.sheetId, col, group[0] + 1, "horizontal", undefined);
50295
+ }
50296
+ }
50297
+ if (group[group.length - 1] === 0) {
50298
+ for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
50299
+ this.history.update("borders", cmd.sheetId, col, 0, "horizontal", undefined);
50300
+ }
50301
+ }
50302
+ const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
50303
+ this.clearInsideBorders(cmd.sheetId, [zone]);
50304
+ this.shiftBordersVertically(cmd.sheetId, group[0] + 1, -group.length);
50223
50305
  }
50224
50306
  }
50225
50307
  break;
@@ -50526,6 +50608,18 @@ class BordersPlugin extends CorePlugin {
50526
50608
  }
50527
50609
  }
50528
50610
  }
50611
+ /**
50612
+ * Remove the borders inside of a zone
50613
+ */
50614
+ clearInsideBorders(sheetId, zones) {
50615
+ for (let zone of zones) {
50616
+ for (let row = zone.top; row <= zone.bottom; row++) {
50617
+ for (let col = zone.left; col <= zone.right; col++) {
50618
+ this.history.update("borders", sheetId, col, row, undefined);
50619
+ }
50620
+ }
50621
+ }
50622
+ }
50529
50623
  /**
50530
50624
  * Add a border to the existing one to a cell
50531
50625
  */
@@ -61767,6 +61861,19 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
61767
61861
 
61768
61862
  class InsertPivotPlugin extends UIPlugin {
61769
61863
  static getters = [];
61864
+ allowDispatch(cmd) {
61865
+ switch (cmd.type) {
61866
+ case "DUPLICATE_PIVOT_IN_NEW_SHEET":
61867
+ if (!this.getters.isExistingPivot(cmd.pivotId)) {
61868
+ return "PivotIdNotFound" /* CommandResult.PivotIdNotFound */;
61869
+ }
61870
+ if (!this.getters.getPivot(cmd.pivotId).isValid()) {
61871
+ return "PivotInError" /* CommandResult.PivotInError */;
61872
+ }
61873
+ break;
61874
+ }
61875
+ return "Success" /* CommandResult.Success */;
61876
+ }
61770
61877
  handle(cmd) {
61771
61878
  switch (cmd.type) {
61772
61879
  case "INSERT_NEW_PIVOT":
@@ -65995,11 +66102,6 @@ class BottomBarSheet extends Component {
65995
66102
  editionState = "initializing";
65996
66103
  DOMFocusableElementStore;
65997
66104
  setup() {
65998
- onMounted(() => {
65999
- if (this.isSheetActive) {
66000
- this.scrollToSheet();
66001
- }
66002
- });
66003
66105
  onPatched(() => {
66004
66106
  if (this.sheetNameRef.el && this.state.isEditing && this.editionState === "initializing") {
66005
66107
  this.editionState = "editing";
@@ -66008,6 +66110,11 @@ class BottomBarSheet extends Component {
66008
66110
  });
66009
66111
  this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
66010
66112
  useExternalListener(window, "click", () => (this.state.pickerOpened = false));
66113
+ useEffect((sheetId) => {
66114
+ if (this.props.sheetId === sheetId) {
66115
+ this.scrollToSheet();
66116
+ }
66117
+ }, () => [this.env.model.getters.getActiveSheetId()]);
66011
66118
  }
66012
66119
  focusInputAndSelectContent() {
66013
66120
  if (!this.state.isEditing || !this.sheetNameRef.el)
@@ -66019,7 +66126,10 @@ class BottomBarSheet extends Component {
66019
66126
  }
66020
66127
  }
66021
66128
  scrollToSheet() {
66022
- this.sheetDivRef.el?.scrollIntoView?.();
66129
+ this.sheetDivRef.el?.scrollIntoView?.({
66130
+ behavior: "smooth",
66131
+ inline: "nearest",
66132
+ });
66023
66133
  }
66024
66134
  onFocusOut() {
66025
66135
  if (this.state.isEditing && this.editionState !== "initializing") {
@@ -66049,11 +66159,11 @@ class BottomBarSheet extends Component {
66049
66159
  if (ev.key === "Enter") {
66050
66160
  ev.preventDefault();
66051
66161
  this.stopEdition();
66052
- this.DOMFocusableElementStore.focus();
66162
+ this.DOMFocusableElementStore.focusableElement?.focus();
66053
66163
  }
66054
66164
  if (ev.key === "Escape") {
66055
66165
  this.cancelEdition();
66056
- this.DOMFocusableElementStore.focus();
66166
+ this.DOMFocusableElementStore.focusableElement?.focus();
66057
66167
  }
66058
66168
  }
66059
66169
  onMouseEventSheetName(ev) {
@@ -71677,7 +71787,12 @@ function createSharedStrings(strings) {
71677
71787
  ["count", strings.length],
71678
71788
  ["uniqueCount", strings.length],
71679
71789
  ];
71680
- const stringNodes = strings.map((string) => escapeXml /*xml*/ `<si><t>${string}</t></si>`);
71790
+ const stringNodes = strings.map((string) => {
71791
+ if (string.trim() !== string) {
71792
+ return escapeXml /*xml*/ `<si><t xml:space="preserve">${string}</t></si>`;
71793
+ }
71794
+ return escapeXml /*xml*/ `<si><t>${string}</t></si>`;
71795
+ });
71681
71796
  const xml = escapeXml /*xml*/ `
71682
71797
  <sst ${formatAttributes(namespaces)}>
71683
71798
  ${joinXmlNodes(stringNodes)}
@@ -71922,7 +72037,7 @@ class Model extends EventBus {
71922
72037
  // events
71923
72038
  this.setupSessionEvents();
71924
72039
  this.joinSession();
71925
- if (config.snapshotRequested) {
72040
+ if (config.snapshotRequested || (data["[Content_Types].xml"] && !this.getters.isReadonly())) {
71926
72041
  const startSnapshot = performance.now();
71927
72042
  console.debug("Snapshot requested");
71928
72043
  this.session.snapshot(this.exportData());
@@ -72420,6 +72535,8 @@ const helpers = {
72420
72535
  splitReference,
72421
72536
  formatTickValue,
72422
72537
  sanitizeSheetName,
72538
+ isNumber,
72539
+ isDateTime,
72423
72540
  };
72424
72541
  const links = {
72425
72542
  isMarkdownLink,
@@ -72512,6 +72629,6 @@ const constants = {
72512
72629
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
72513
72630
 
72514
72631
 
72515
- __info__.version = "18.0.8";
72516
- __info__.date = "2024-12-19T07:50:36.150Z";
72517
- __info__.hash = "7cf34a6";
72632
+ __info__.version = "18.0.10";
72633
+ __info__.date = "2025-01-15T08:05:47.616Z";
72634
+ __info__.hash = "94c45c7";