@odoo/o-spreadsheet 18.1.0 → 18.1.2

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.1.0
6
- * @date 2024-12-26T06:37:07.879Z
7
- * @hash c520e89
5
+ * @version 18.1.2
6
+ * @date 2025-01-15T08:06:07.728Z
7
+ * @hash 002aa4a
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';
@@ -3709,6 +3709,7 @@ var CommandResult;
3709
3709
  CommandResult["SheetIsHidden"] = "SheetIsHidden";
3710
3710
  CommandResult["InvalidTableResize"] = "InvalidTableResize";
3711
3711
  CommandResult["PivotIdNotFound"] = "PivotIdNotFound";
3712
+ CommandResult["PivotInError"] = "PivotInError";
3712
3713
  CommandResult["EmptyName"] = "EmptyName";
3713
3714
  CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
3714
3715
  CommandResult["InvalidDefinition"] = "InvalidDefinition";
@@ -7477,18 +7478,18 @@ function predictLinearValues(Y, X, newX, computeIntercept) {
7477
7478
  });
7478
7479
  return newY.length === newX.length ? newY : transposeMatrix(newY);
7479
7480
  }
7480
- function getMovingAverageValues(dataset, windowSize = DEFAULT_WINDOW_SIZE) {
7481
+ function getMovingAverageValues(dataset, labels, windowSize = DEFAULT_WINDOW_SIZE) {
7481
7482
  const values = [];
7482
7483
  // Fill the starting values with null until we have a full window
7483
7484
  for (let i = 0; i < windowSize - 1; i++) {
7484
- values.push(null);
7485
+ values.push({ x: labels[i], y: NaN });
7485
7486
  }
7486
7487
  for (let i = 0; i <= dataset.length - windowSize; i++) {
7487
7488
  let sum = 0;
7488
7489
  for (let j = i; j < i + windowSize; j++) {
7489
7490
  sum += dataset[j];
7490
7491
  }
7491
- values.push(sum / windowSize);
7492
+ values.push({ x: labels[i + windowSize - 1], y: sum / windowSize });
7492
7493
  }
7493
7494
  return values;
7494
7495
  }
@@ -19930,6 +19931,17 @@ const TEXT = {
19930
19931
  },
19931
19932
  isExported: true,
19932
19933
  };
19934
+ // -----------------------------------------------------------------------------
19935
+ // VALUE
19936
+ // -----------------------------------------------------------------------------
19937
+ const VALUE = {
19938
+ description: _t("Converts a string to a numeric value."),
19939
+ args: [arg("value (number)", _t("the string to be converted"))],
19940
+ compute: function (value) {
19941
+ return toNumber(value, this.locale);
19942
+ },
19943
+ isExported: true,
19944
+ };
19933
19945
 
19934
19946
  var text = /*#__PURE__*/Object.freeze({
19935
19947
  __proto__: null,
@@ -19952,7 +19964,8 @@ var text = /*#__PURE__*/Object.freeze({
19952
19964
  TEXT: TEXT,
19953
19965
  TEXTJOIN: TEXTJOIN,
19954
19966
  TRIM: TRIM,
19955
- UPPER: UPPER
19967
+ UPPER: UPPER,
19968
+ VALUE: VALUE
19956
19969
  });
19957
19970
 
19958
19971
  // -----------------------------------------------------------------------------
@@ -24140,7 +24153,7 @@ function convertWidthFromExcel(width) {
24140
24153
  return width;
24141
24154
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
24142
24155
  }
24143
- function extractStyle(data, styleId, formatId, borderId) {
24156
+ function extractStyle(data, content, styleId, formatId, borderId) {
24144
24157
  const style = styleId ? data.styles[styleId] : {};
24145
24158
  const format = formatId ? data.formats[formatId] : undefined;
24146
24159
  const styles = {
@@ -24162,7 +24175,7 @@ function extractStyle(data, styleId, formatId, borderId) {
24162
24175
  vertical: style.verticalAlign
24163
24176
  ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
24164
24177
  : undefined,
24165
- wrapText: style.wrapping === "wrap" || undefined,
24178
+ wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
24166
24179
  },
24167
24180
  };
24168
24181
  styles.font["strike"] = !!style?.strikethrough || undefined;
@@ -24393,7 +24406,7 @@ function convertFigure(figure, id, sheetData) {
24393
24406
  return undefined;
24394
24407
  }
24395
24408
  function isChartData(data) {
24396
- return "dataSets" in data;
24409
+ return "dataSets" in data && data.dataSets.length > 0;
24397
24410
  }
24398
24411
  function isImageData(data) {
24399
24412
  return "imageSrc" in data;
@@ -24739,9 +24752,8 @@ function convertRows(sheet, numberOfRows, headerGroups) {
24739
24752
  }
24740
24753
  return rows;
24741
24754
  }
24742
- /** Remove newlines (\n) in shared strings, We do not support them */
24743
24755
  function convertSharedStrings(xlsxSharedStrings) {
24744
- return xlsxSharedStrings.map((str) => str.replace(/\n/g, ""));
24756
+ return xlsxSharedStrings.map(replaceNewLines);
24745
24757
  }
24746
24758
  function convertCells(sheet, data, sheetDims, warningManager) {
24747
24759
  const cells = {};
@@ -25829,15 +25841,10 @@ class XlsxMiscExtractor extends XlsxBaseExtractor {
25829
25841
  getSharedStrings() {
25830
25842
  return this.mapOnElements({ parent: this.rootFile.file.xml, query: "si" }, (ssElement) => {
25831
25843
  // Shared string can either be a simple text, or a rich text (text with formatting, possibly in multiple parts)
25832
- if (ssElement.children[0].tagName === "t") {
25833
- return this.extractTextContent(ssElement) || "";
25834
- }
25835
25844
  // We don't support rich text formatting, we'll only extract the text
25836
- else {
25837
- return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
25838
- return this.extractTextContent(textElement) || "";
25839
- }).join("");
25840
- }
25845
+ return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
25846
+ return this.extractTextContent(textElement) || "";
25847
+ }).join("");
25841
25848
  });
25842
25849
  }
25843
25850
  }
@@ -27478,6 +27485,13 @@ migrationStepRegistry
27478
27485
  }
27479
27486
  return data;
27480
27487
  },
27488
+ })
27489
+ .add("migration_24", {
27490
+ // Empty migration to allow odoo migrate pivot custom sorting.
27491
+ versionFrom: "24",
27492
+ migrate(data) {
27493
+ return data;
27494
+ },
27481
27495
  });
27482
27496
  function fixOverlappingFilters(data) {
27483
27497
  for (let sheet of data.sheets || []) {
@@ -27505,7 +27519,7 @@ function fixOverlappingFilters(data) {
27505
27519
  * a breaking change is made in the way the state is handled, and an upgrade
27506
27520
  * function should be defined
27507
27521
  */
27508
- const CURRENT_VERSION = 24;
27522
+ const CURRENT_VERSION = 25;
27509
27523
  const INITIAL_SHEET_ID = "Sheet1";
27510
27524
  /**
27511
27525
  * This function tries to load anything that could look like a valid
@@ -28406,12 +28420,12 @@ function getTrendDatasetForLineChart(config, data, labels, axisType, locale) {
28406
28420
  }
28407
28421
  const numberOfStep = 5 * trendLabels.length;
28408
28422
  const step = (xmax - xmin) / numberOfStep;
28409
- const newLabels = range(xmin, xmax + step / 2, step);
28410
- const newValues = interpolateData(config, filteredValues, filteredLabels, newLabels);
28411
- if (!newValues.length) {
28423
+ const trendNewLabels = range(xmin, xmax + step / 2, step);
28424
+ const trendValues = interpolateData(config, filteredValues, filteredLabels, trendNewLabels);
28425
+ if (!trendValues.length) {
28412
28426
  return;
28413
28427
  }
28414
- return newValues;
28428
+ return trendValues;
28415
28429
  }
28416
28430
  function interpolateData(config, values, labels, newLabels) {
28417
28431
  if (values.length < 2 || labels.length < 2 || newLabels.length === 0) {
@@ -28427,13 +28441,16 @@ function interpolateData(config, values, labels, newLabels) {
28427
28441
  case "polynomial": {
28428
28442
  const order = config.order;
28429
28443
  if (!order) {
28430
- return Array.from({ length: newLabels.length }, () => NaN);
28444
+ return newLabels.map((x) => ({ x, y: NaN }));
28431
28445
  }
28432
28446
  if (order === 1) {
28433
- return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
28447
+ return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0].map((y, i) => ({ x: newLabels[i], y }));
28434
28448
  }
28435
28449
  const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
28436
- return normalizedNewLabels.map((v) => evaluatePolynomial(coeffs, v, order));
28450
+ return normalizedNewLabels.map((x, i) => ({
28451
+ x: newLabels[i],
28452
+ y: evaluatePolynomial(coeffs, x, order),
28453
+ }));
28437
28454
  }
28438
28455
  case "exponential": {
28439
28456
  const positiveLogValues = [];
@@ -28445,22 +28462,22 @@ function interpolateData(config, values, labels, newLabels) {
28445
28462
  }
28446
28463
  }
28447
28464
  if (!filteredLabels.length) {
28448
- return Array.from({ length: newLabels.length }, () => NaN);
28465
+ return newLabels.map((x) => ({ x, y: NaN }));
28449
28466
  }
28450
- return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0];
28467
+ return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0].map((y, i) => ({ x: newLabels[i], y }));
28451
28468
  }
28452
28469
  case "logarithmic": {
28453
- return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0];
28470
+ return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0].map((y, i) => ({ x: newLabels[i], y }));
28454
28471
  }
28455
28472
  case "trailingMovingAverage": {
28456
- return getMovingAverageValues(values, config.window);
28473
+ return getMovingAverageValues(values, labels, config.window);
28457
28474
  }
28458
28475
  default:
28459
- return Array.from({ length: newLabels.length }, () => NaN);
28476
+ return newLabels.map((x) => ({ x, y: NaN }));
28460
28477
  }
28461
28478
  }
28462
28479
  catch (e) {
28463
- return Array.from({ length: newLabels.length }, () => NaN);
28480
+ return newLabels.map((x) => ({ x, y: NaN }));
28464
28481
  }
28465
28482
  }
28466
28483
  function getChartAxisType(chart, labelRange, getters) {
@@ -28696,7 +28713,7 @@ function getChartDatasetValues(getters, dataSets) {
28696
28713
  // then using the classical aggregation method to sum the values.
28697
28714
  data.fill(1);
28698
28715
  }
28699
- else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), getters.getLocale()))) {
28716
+ else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), DEFAULT_LOCALE))) {
28700
28717
  continue;
28701
28718
  }
28702
28719
  datasetValues.push({ data, label });
@@ -29090,6 +29107,7 @@ function getWaterfallChartLegend(definition, args) {
29090
29107
  return legendValues;
29091
29108
  },
29092
29109
  },
29110
+ onClick: () => { }, // Disables click interaction with the waterfall chart legend items
29093
29111
  };
29094
29112
  }
29095
29113
  function getRadarChartLegend(definition, args) {
@@ -29231,14 +29249,19 @@ function getLineChartScales(definition, args) {
29231
29249
  /* We add a second x axis here to draw the trend lines, with the labels length being
29232
29250
  * set so that the second axis points match the classical x axis
29233
29251
  */
29234
- const maxLength = Math.max(...trendDatasets.map((trendDataset) => trendDataset?.length || 0));
29235
29252
  scales[TREND_LINE_XAXIS_ID] = {
29236
29253
  ...scales.x,
29237
- type: "category",
29238
- labels: range(0, maxLength).map((x) => x.toString()),
29239
- offset: false,
29240
29254
  display: false,
29241
29255
  };
29256
+ if (axisType === "category" || axisType === "time") {
29257
+ /* We add a second x axis here to draw the trend lines, with the labels length being
29258
+ * set so that the second axis points match the classical x axis
29259
+ */
29260
+ const maxLength = Math.max(...trendDatasets.map((trendDataset) => trendDataset?.length || 0));
29261
+ scales[TREND_LINE_XAXIS_ID]["type"] = "category";
29262
+ scales[TREND_LINE_XAXIS_ID]["labels"] = range(0, maxLength).map((x) => x.toString());
29263
+ scales[TREND_LINE_XAXIS_ID]["offset"] = false;
29264
+ }
29242
29265
  }
29243
29266
  return scales;
29244
29267
  }
@@ -29508,7 +29531,9 @@ function getLineChartTooltip(definition, args) {
29508
29531
  if (axisType === "linear") {
29509
29532
  tooltip.callbacks.label = (tooltipItem) => {
29510
29533
  const dataSetPoint = tooltipItem.parsed.y;
29511
- let label = tooltipItem.parsed.x;
29534
+ let label = tooltipItem.dataset.xAxisID === TREND_LINE_XAXIS_ID
29535
+ ? ""
29536
+ : tooltipItem.parsed.x;
29512
29537
  if (typeof label === "string" && isNumber(label, locale)) {
29513
29538
  label = toNumber(label, locale);
29514
29539
  }
@@ -30201,7 +30226,11 @@ function createGaugeChartRuntime(chart, getters) {
30201
30226
  colors.push(chartColors.upperColor);
30202
30227
  return {
30203
30228
  background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
30204
- title: chart.title ?? { text: "" },
30229
+ title: {
30230
+ ...chart.title,
30231
+ // chart titles are extracted from .json files and they are translated at runtime here
30232
+ text: _t(chart.title.text ?? ""),
30233
+ },
30205
30234
  minValue: {
30206
30235
  value: minValue,
30207
30236
  label: formatValue(minValue, { locale, format }),
@@ -35332,12 +35361,20 @@ function fontSizeMenuBuilder() {
35332
35361
  });
35333
35362
  }
35334
35363
  function isAutomaticFormatSelected(env) {
35335
- const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
35336
- return !activeCell || !activeCell.format;
35364
+ const activePosition = env.model.getters.getActivePosition();
35365
+ const pivotCell = env.model.getters.getPivotCellFromPosition(activePosition);
35366
+ if (pivotCell.type === "VALUE") {
35367
+ return !env.model.getters.getEvaluatedCell(activePosition).format;
35368
+ }
35369
+ return !env.model.getters.getCell(activePosition)?.format;
35337
35370
  }
35338
35371
  function isFormatSelected(env, format) {
35339
- const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
35340
- return activeCell?.format === format;
35372
+ const activePosition = env.model.getters.getActivePosition();
35373
+ const pivotCell = env.model.getters.getPivotCellFromPosition(activePosition);
35374
+ if (pivotCell.type === "VALUE") {
35375
+ return env.model.getters.getEvaluatedCell(activePosition).format === format;
35376
+ }
35377
+ return env.model.getters.getCell(activePosition)?.format === format;
35341
35378
  }
35342
35379
  function isFontSizeSelected(env, fontSize) {
35343
35380
  const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
@@ -39676,14 +39713,11 @@ class ChartPanel extends Component {
39676
39713
  }
39677
39714
 
39678
39715
  class DOMFocusableElementStore {
39679
- mutators = ["setFocusableElement", "focus"];
39716
+ mutators = ["setFocusableElement"];
39680
39717
  focusableElement = undefined;
39681
39718
  setFocusableElement(element) {
39682
39719
  this.focusableElement = element;
39683
39720
  }
39684
- focus() {
39685
- this.focusableElement?.focus();
39686
- }
39687
39721
  }
39688
39722
 
39689
39723
  css /* scss */ `
@@ -40331,7 +40365,7 @@ class Composer extends Component {
40331
40365
  if (document.activeElement === this.contentHelper.el &&
40332
40366
  this.props.composerStore.editionMode === "inactive" &&
40333
40367
  !this.props.isDefaultFocus) {
40334
- this.DOMFocusableElementStore.focus();
40368
+ this.DOMFocusableElementStore.focusableElement?.focus();
40335
40369
  }
40336
40370
  });
40337
40371
  useEffect(() => {
@@ -44312,16 +44346,21 @@ class TextInput extends Component {
44312
44346
  }
44313
44347
  this.inputRef.el?.blur();
44314
44348
  }
44315
- focusInputAndSelectContent() {
44316
- const inputEl = this.inputRef.el;
44317
- if (!inputEl)
44318
- return;
44319
- // The onFocus event selects all text in the input.
44320
- // The subsequent mouseup event can deselect this text,
44321
- // so t-on-mouseup.prevent.stop is used to prevent this
44322
- // default behavior and preserve the selection.
44323
- inputEl.focus();
44324
- inputEl.select();
44349
+ onMouseDown(ev) {
44350
+ // Stop the event if the input is not focused, we handle everything in onMouseUp
44351
+ if (ev.target !== document.activeElement) {
44352
+ ev.preventDefault();
44353
+ ev.stopPropagation();
44354
+ }
44355
+ }
44356
+ onMouseUp(ev) {
44357
+ const target = ev.target;
44358
+ if (target !== document.activeElement) {
44359
+ target.focus();
44360
+ target.select();
44361
+ ev.preventDefault();
44362
+ ev.stopPropagation();
44363
+ }
44325
44364
  }
44326
44365
  }
44327
44366
 
@@ -44874,7 +44913,16 @@ class PivotTitleSection extends Component {
44874
44913
  newPivotId,
44875
44914
  newSheetId,
44876
44915
  });
44877
- const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
44916
+ let text;
44917
+ if (result.isSuccessful) {
44918
+ text = _t("Pivot duplicated.");
44919
+ }
44920
+ else if (result.isCancelledBecause("PivotInError" /* CommandResult.PivotInError */)) {
44921
+ text = _t("Cannot duplicate a pivot in error.");
44922
+ }
44923
+ else {
44924
+ text = _t("Pivot duplication failed.");
44925
+ }
44878
44926
  const type = result.isSuccessful ? "success" : "danger";
44879
44927
  this.env.notifyUser({
44880
44928
  text,
@@ -46213,7 +46261,9 @@ class PivotSidePanelStore extends SpreadsheetStore {
46213
46261
  pivot: this.draft,
46214
46262
  });
46215
46263
  this.draft = null;
46216
- if (!this.alreadyNotified && !this.isDynamicPivotInViewport()) {
46264
+ if (!this.alreadyNotified &&
46265
+ !this.isDynamicPivotInViewport() &&
46266
+ this.isStaticPivotInViewport()) {
46217
46267
  const formulaId = this.getters.getPivotFormulaId(this.pivotId);
46218
46268
  const pivotExample = `=PIVOT(${formulaId})`;
46219
46269
  this.alreadyNotified = true;
@@ -46281,6 +46331,18 @@ class PivotSidePanelStore extends SpreadsheetStore {
46281
46331
  }
46282
46332
  return false;
46283
46333
  }
46334
+ isStaticPivotInViewport() {
46335
+ for (const position of this.getters.getVisibleCellPositions()) {
46336
+ const cell = this.getters.getCell(position);
46337
+ if (cell?.isFormula) {
46338
+ const pivotFunction = getFirstPivotFunction(cell.compiledFormula.tokens);
46339
+ if (pivotFunction && pivotFunction.functionName !== "PIVOT") {
46340
+ return true;
46341
+ }
46342
+ }
46343
+ }
46344
+ return false;
46345
+ }
46284
46346
  addDefaultDateTimeGranularity(fields, definition) {
46285
46347
  const { columns, rows } = definition;
46286
46348
  const columnsWithGranularity = deepCopy(columns);
@@ -51693,7 +51755,7 @@ class Grid extends Component {
51693
51755
  this.cellPopovers = useStore(CellPopoverStore);
51694
51756
  useEffect(() => {
51695
51757
  if (!this.sidePanel.isOpen) {
51696
- this.DOMFocusableElementStore.focus();
51758
+ this.DOMFocusableElementStore.focusableElement?.focus();
51697
51759
  }
51698
51760
  }, () => [this.sidePanel.isOpen]);
51699
51761
  }
@@ -51899,7 +51961,7 @@ class Grid extends Component {
51899
51961
  focusDefaultElement() {
51900
51962
  if (!this.env.model.getters.getSelectedFigureId() &&
51901
51963
  this.composerFocusStore.activeComposer.editionMode === "inactive") {
51902
- this.DOMFocusableElementStore.focus();
51964
+ this.DOMFocusableElementStore.focusableElement?.focus();
51903
51965
  }
51904
51966
  }
51905
51967
  get gridEl() {
@@ -52436,10 +52498,34 @@ class BordersPlugin extends CorePlugin {
52436
52498
  const elements = [...cmd.elements].sort((a, b) => b - a);
52437
52499
  for (const group of groupConsecutive(elements)) {
52438
52500
  if (cmd.dimension === "COL") {
52439
- this.shiftBordersHorizontally(cmd.sheetId, group[group.length - 1] + 1, -group.length);
52501
+ if (group[0] >= this.getters.getNumberCols(cmd.sheetId)) {
52502
+ for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
52503
+ this.history.update("borders", cmd.sheetId, group[0] + 1, row, "vertical", undefined);
52504
+ }
52505
+ }
52506
+ if (group[group.length - 1] === 0) {
52507
+ for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
52508
+ this.history.update("borders", cmd.sheetId, 0, row, "vertical", undefined);
52509
+ }
52510
+ }
52511
+ const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
52512
+ this.clearInsideBorders(cmd.sheetId, [zone]);
52513
+ this.shiftBordersHorizontally(cmd.sheetId, group[0] + 1, -group.length);
52440
52514
  }
52441
52515
  else {
52442
- this.shiftBordersVertically(cmd.sheetId, group[group.length - 1] + 1, -group.length);
52516
+ if (group[0] >= this.getters.getNumberRows(cmd.sheetId)) {
52517
+ for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
52518
+ this.history.update("borders", cmd.sheetId, col, group[0] + 1, "horizontal", undefined);
52519
+ }
52520
+ }
52521
+ if (group[group.length - 1] === 0) {
52522
+ for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
52523
+ this.history.update("borders", cmd.sheetId, col, 0, "horizontal", undefined);
52524
+ }
52525
+ }
52526
+ const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
52527
+ this.clearInsideBorders(cmd.sheetId, [zone]);
52528
+ this.shiftBordersVertically(cmd.sheetId, group[0] + 1, -group.length);
52443
52529
  }
52444
52530
  }
52445
52531
  break;
@@ -52746,6 +52832,18 @@ class BordersPlugin extends CorePlugin {
52746
52832
  }
52747
52833
  }
52748
52834
  }
52835
+ /**
52836
+ * Remove the borders inside of a zone
52837
+ */
52838
+ clearInsideBorders(sheetId, zones) {
52839
+ for (let zone of zones) {
52840
+ for (let row = zone.top; row <= zone.bottom; row++) {
52841
+ for (let col = zone.left; col <= zone.right; col++) {
52842
+ this.history.update("borders", sheetId, col, row, undefined);
52843
+ }
52844
+ }
52845
+ }
52846
+ }
52749
52847
  /**
52750
52848
  * Add a border to the existing one to a cell
52751
52849
  */
@@ -63942,6 +64040,19 @@ class HeaderVisibilityUIPlugin extends UIPlugin {
63942
64040
 
63943
64041
  class InsertPivotPlugin extends UIPlugin {
63944
64042
  static getters = [];
64043
+ allowDispatch(cmd) {
64044
+ switch (cmd.type) {
64045
+ case "DUPLICATE_PIVOT_IN_NEW_SHEET":
64046
+ if (!this.getters.isExistingPivot(cmd.pivotId)) {
64047
+ return "PivotIdNotFound" /* CommandResult.PivotIdNotFound */;
64048
+ }
64049
+ if (!this.getters.getPivot(cmd.pivotId).isValid()) {
64050
+ return "PivotInError" /* CommandResult.PivotInError */;
64051
+ }
64052
+ break;
64053
+ }
64054
+ return "Success" /* CommandResult.Success */;
64055
+ }
63945
64056
  handle(cmd) {
63946
64057
  switch (cmd.type) {
63947
64058
  case "INSERT_NEW_PIVOT":
@@ -68178,11 +68289,6 @@ class BottomBarSheet extends Component {
68178
68289
  editionState = "initializing";
68179
68290
  DOMFocusableElementStore;
68180
68291
  setup() {
68181
- onMounted(() => {
68182
- if (this.isSheetActive) {
68183
- this.scrollToSheet();
68184
- }
68185
- });
68186
68292
  onPatched(() => {
68187
68293
  if (this.sheetNameRef.el && this.state.isEditing && this.editionState === "initializing") {
68188
68294
  this.editionState = "editing";
@@ -68191,6 +68297,11 @@ class BottomBarSheet extends Component {
68191
68297
  });
68192
68298
  this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
68193
68299
  useExternalListener(window, "click", () => (this.state.pickerOpened = false));
68300
+ useEffect((sheetId) => {
68301
+ if (this.props.sheetId === sheetId) {
68302
+ this.scrollToSheet();
68303
+ }
68304
+ }, () => [this.env.model.getters.getActiveSheetId()]);
68194
68305
  }
68195
68306
  focusInputAndSelectContent() {
68196
68307
  if (!this.state.isEditing || !this.sheetNameRef.el)
@@ -68202,7 +68313,10 @@ class BottomBarSheet extends Component {
68202
68313
  }
68203
68314
  }
68204
68315
  scrollToSheet() {
68205
- this.sheetDivRef.el?.scrollIntoView?.();
68316
+ this.sheetDivRef.el?.scrollIntoView?.({
68317
+ behavior: "smooth",
68318
+ inline: "nearest",
68319
+ });
68206
68320
  }
68207
68321
  onFocusOut() {
68208
68322
  if (this.state.isEditing && this.editionState !== "initializing") {
@@ -68232,11 +68346,11 @@ class BottomBarSheet extends Component {
68232
68346
  if (ev.key === "Enter") {
68233
68347
  ev.preventDefault();
68234
68348
  this.stopEdition();
68235
- this.DOMFocusableElementStore.focus();
68349
+ this.DOMFocusableElementStore.focusableElement?.focus();
68236
68350
  }
68237
68351
  if (ev.key === "Escape") {
68238
68352
  this.cancelEdition();
68239
- this.DOMFocusableElementStore.focus();
68353
+ this.DOMFocusableElementStore.focusableElement?.focus();
68240
68354
  }
68241
68355
  }
68242
68356
  onMouseEventSheetName(ev) {
@@ -73612,7 +73726,7 @@ function addRows(construct, data, sheet) {
73612
73726
  if (content || styleId || formatId || borderId || value !== undefined) {
73613
73727
  const attributes = [["r", xc]];
73614
73728
  // style
73615
- const id = normalizeStyle(construct, extractStyle(data, styleId, formatId, borderId));
73729
+ const id = normalizeStyle(construct, extractStyle(data, content, styleId, formatId, borderId));
73616
73730
  // don't add style if default
73617
73731
  if (id) {
73618
73732
  attributes.push(["s", id]);
@@ -73966,7 +74080,12 @@ function createSharedStrings(strings) {
73966
74080
  ["count", strings.length],
73967
74081
  ["uniqueCount", strings.length],
73968
74082
  ];
73969
- const stringNodes = strings.map((string) => escapeXml /*xml*/ `<si><t>${string}</t></si>`);
74083
+ const stringNodes = strings.map((string) => {
74084
+ if (string.trim() !== string) {
74085
+ return escapeXml /*xml*/ `<si><t xml:space="preserve">${string}</t></si>`;
74086
+ }
74087
+ return escapeXml /*xml*/ `<si><t>${string}</t></si>`;
74088
+ });
73970
74089
  const xml = escapeXml /*xml*/ `
73971
74090
  <sst ${formatAttributes(namespaces)}>
73972
74091
  ${joinXmlNodes(stringNodes)}
@@ -74206,7 +74325,7 @@ class Model extends EventBus {
74206
74325
  // events
74207
74326
  this.setupSessionEvents();
74208
74327
  this.joinSession();
74209
- if (config.snapshotRequested) {
74328
+ if (config.snapshotRequested || (data["[Content_Types].xml"] && !this.getters.isReadonly())) {
74210
74329
  const startSnapshot = performance.now();
74211
74330
  console.debug("Snapshot requested");
74212
74331
  this.session.snapshot(this.exportData());
@@ -74693,6 +74812,8 @@ const helpers = {
74693
74812
  areDomainArgsFieldsValid,
74694
74813
  splitReference,
74695
74814
  sanitizeSheetName,
74815
+ isNumber,
74816
+ isDateTime,
74696
74817
  };
74697
74818
  const links = {
74698
74819
  isMarkdownLink,
@@ -74787,6 +74908,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
74787
74908
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, 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 };
74788
74909
 
74789
74910
 
74790
- __info__.version = "18.1.0";
74791
- __info__.date = "2024-12-26T06:37:07.879Z";
74792
- __info__.hash = "c520e89";
74911
+ __info__.version = "18.1.2";
74912
+ __info__.date = "2025-01-15T08:06:07.728Z";
74913
+ __info__.hash = "002aa4a";