@odoo/o-spreadsheet 18.1.17 → 18.1.19

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.17
6
- * @date 2025-04-25T08:08:46.599Z
7
- * @hash a63687f
5
+ * @version 18.1.19
6
+ * @date 2025-05-12T05:26:05.861Z
7
+ * @hash 44cc170
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';
@@ -3760,6 +3760,7 @@ var CommandResult;
3760
3760
  CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
3761
3761
  CommandResult["InvalidDefinition"] = "InvalidDefinition";
3762
3762
  CommandResult["InvalidColor"] = "InvalidColor";
3763
+ CommandResult["InvalidPivotDataSet"] = "InvalidPivotDataSet";
3763
3764
  })(CommandResult || (CommandResult = {}));
3764
3765
 
3765
3766
  const DEFAULT_LOCALES = [
@@ -6270,6 +6271,25 @@ function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
6270
6271
  })
6271
6272
  .filter(isDefined);
6272
6273
  }
6274
+ function getNextSheetName(existingNames, baseName = "Sheet") {
6275
+ let i = 1;
6276
+ let name = `${baseName}${i}`;
6277
+ while (existingNames.includes(name)) {
6278
+ name = `${baseName}${i}`;
6279
+ i++;
6280
+ }
6281
+ return name;
6282
+ }
6283
+ function getDuplicateSheetName(nameToDuplicate, existingNames) {
6284
+ let i = 1;
6285
+ const baseName = _t("Copy of %s", nameToDuplicate);
6286
+ let name = baseName.toString();
6287
+ while (existingNames.includes(name)) {
6288
+ name = `${baseName} (${i})`;
6289
+ i++;
6290
+ }
6291
+ return name;
6292
+ }
6273
6293
 
6274
6294
  function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
6275
6295
  return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
@@ -7968,6 +7988,24 @@ const monthNumberAdapter = {
7968
7988
  return `${normalizedValue}`;
7969
7989
  },
7970
7990
  };
7991
+ /**
7992
+ * normalizes month number + year
7993
+ */
7994
+ const monthAdapter = {
7995
+ normalizeFunctionValue(value) {
7996
+ const date = toNumber(value, DEFAULT_LOCALE);
7997
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
7998
+ },
7999
+ toValueAndFormat(normalizedValue) {
8000
+ return {
8001
+ value: toNumber(normalizedValue, DEFAULT_LOCALE),
8002
+ format: "mmmm yyyy",
8003
+ };
8004
+ },
8005
+ toFunctionValue(normalizedValue) {
8006
+ return `"${normalizedValue}"`;
8007
+ },
8008
+ };
7971
8009
  /**
7972
8010
  * normalizes quarter number
7973
8011
  */
@@ -8098,6 +8136,7 @@ pivotTimeAdapterRegistry
8098
8136
  .add("day_of_month", nullHandlerDecorator(dayOfMonthAdapter))
8099
8137
  .add("iso_week_number", nullHandlerDecorator(isoWeekNumberAdapter))
8100
8138
  .add("month_number", nullHandlerDecorator(monthNumberAdapter))
8139
+ .add("month", nullHandlerDecorator(monthAdapter))
8101
8140
  .add("quarter_number", nullHandlerDecorator(quarterNumberAdapter))
8102
8141
  .add("day_of_week", nullHandlerDecorator(dayOfWeekAdapter))
8103
8142
  .add("hour_number", nullHandlerDecorator(hourNumberAdapter))
@@ -8277,10 +8316,7 @@ function toNormalizedPivotValue(dimension, groupValue) {
8277
8316
  return normalizer(groupValueString, dimension.granularity);
8278
8317
  }
8279
8318
  function normalizeDateTime(value, granularity) {
8280
- if (!granularity) {
8281
- throw new Error("Missing granularity");
8282
- }
8283
- return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
8319
+ return pivotTimeAdapter(granularity ?? "month").normalizeFunctionValue(value);
8284
8320
  }
8285
8321
  function toFunctionPivotValue(value, dimension) {
8286
8322
  if (value === null) {
@@ -8292,10 +8328,7 @@ function toFunctionPivotValue(value, dimension) {
8292
8328
  return pivotToFunctionValueRegistry.get(dimension.type)(value, dimension.granularity);
8293
8329
  }
8294
8330
  function toFunctionValueDateTime(value, granularity) {
8295
- if (!granularity) {
8296
- throw new Error("Missing granularity");
8297
- }
8298
- return pivotTimeAdapter(granularity).toFunctionValue(value);
8331
+ return pivotTimeAdapter(granularity ?? "month").toFunctionValue(value);
8299
8332
  }
8300
8333
  const pivotNormalizationValueRegistry = new Registry();
8301
8334
  pivotNormalizationValueRegistry
@@ -9610,12 +9643,24 @@ class ComposerFocusStore extends SpreadsheetStore {
9610
9643
  }
9611
9644
 
9612
9645
  const chartJsExtensionRegistry = new Registry();
9613
- /** Return window.Chart, making sure all our extensions are loaded in ChartJS */
9614
- function getChartJSConstructor() {
9615
- if (window.Chart && !window.Chart?.registry.plugins.get("chartShowValuesPlugin")) {
9616
- window.Chart.register(...chartJsExtensionRegistry.getAll());
9646
+ function areChartJSExtensionsLoaded() {
9647
+ return !!window.Chart.registry.plugins.get("chartShowValuesPlugin");
9648
+ }
9649
+ function registerChartJSExtensions() {
9650
+ if (!window.Chart || areChartJSExtensionsLoaded()) {
9651
+ return;
9652
+ }
9653
+ for (const registryItem of chartJsExtensionRegistry.getAll()) {
9654
+ registryItem.register(window.Chart);
9655
+ }
9656
+ }
9657
+ function unregisterChartJsExtensions() {
9658
+ if (!window.Chart) {
9659
+ return;
9660
+ }
9661
+ for (const registryItem of chartJsExtensionRegistry.getAll()) {
9662
+ registryItem.unregister(window.Chart);
9617
9663
  }
9618
- return window.Chart;
9619
9664
  }
9620
9665
 
9621
9666
  const TREND_LINE_XAXIS_ID = "x1";
@@ -10007,7 +10052,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
10007
10052
  const yMin = chart.chartArea.top;
10008
10053
  const textsPositions = {};
10009
10054
  for (const dataset of chart._metasets) {
10010
- if (isTrendLineAxis(dataset.axisID) || dataset.hidden) {
10055
+ if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
10011
10056
  continue;
10012
10057
  }
10013
10058
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10050,7 +10095,7 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
10050
10095
  const xMin = chart.chartArea.left;
10051
10096
  const textsPositions = {};
10052
10097
  for (const dataset of chart._metasets) {
10053
- if (isTrendLineAxis(dataset.axisID)) {
10098
+ if (isTrendLineAxis(dataset.xAxisID)) {
10054
10099
  return; // ignore trend lines
10055
10100
  }
10056
10101
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10156,8 +10201,14 @@ function getNextNonEmptyBar(bars, startIndex) {
10156
10201
  return bars.find((bar, i) => i > startIndex && bar.height !== 0);
10157
10202
  }
10158
10203
 
10159
- chartJsExtensionRegistry.add("chartShowValuesPlugin", chartShowValuesPlugin);
10160
- chartJsExtensionRegistry.add("waterfallLinesPlugin", waterfallLinesPlugin);
10204
+ chartJsExtensionRegistry.add("chartShowValuesPlugin", {
10205
+ register: (Chart) => Chart.register(chartShowValuesPlugin),
10206
+ unregister: (Chart) => Chart.unregister(chartShowValuesPlugin),
10207
+ });
10208
+ chartJsExtensionRegistry.add("waterfallLinesPlugin", {
10209
+ register: (Chart) => Chart.register(waterfallLinesPlugin),
10210
+ unregister: (Chart) => Chart.unregister(waterfallLinesPlugin),
10211
+ });
10161
10212
  class ChartJsComponent extends Component {
10162
10213
  static template = "o-spreadsheet-ChartJsComponent";
10163
10214
  static props = {
@@ -10166,6 +10217,7 @@ class ChartJsComponent extends Component {
10166
10217
  canvas = useRef("graphContainer");
10167
10218
  chart;
10168
10219
  currentRuntime;
10220
+ currentDevicePixelRatio = window.devicePixelRatio;
10169
10221
  get background() {
10170
10222
  return this.chartRuntime.background;
10171
10223
  }
@@ -10199,13 +10251,16 @@ class ChartJsComponent extends Component {
10199
10251
  }
10200
10252
  this.currentRuntime = runtime;
10201
10253
  }
10254
+ else if (this.currentDevicePixelRatio !== window.devicePixelRatio) {
10255
+ this.currentDevicePixelRatio = window.devicePixelRatio;
10256
+ this.updateChartJs(deepCopy(this.currentRuntime.chartJsConfig));
10257
+ }
10202
10258
  });
10203
10259
  }
10204
10260
  createChart(chartData) {
10205
10261
  const canvas = this.canvas.el;
10206
10262
  const ctx = canvas.getContext("2d");
10207
- const Chart = getChartJSConstructor();
10208
- this.chart = new Chart(ctx, chartData);
10263
+ this.chart = new window.Chart(ctx, chartData);
10209
10264
  }
10210
10265
  updateChartJs(chartData) {
10211
10266
  if (chartData.data && chartData.data.datasets) {
@@ -10454,9 +10509,11 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
10454
10509
  };
10455
10510
  function drawScoreChart(structure, canvas) {
10456
10511
  const ctx = canvas.getContext("2d");
10457
- canvas.width = structure.canvas.width;
10458
- const availableWidth = canvas.width - CHART_PADDING$1 * 2;
10459
- canvas.height = structure.canvas.height;
10512
+ const dpr = window.devicePixelRatio || 1;
10513
+ canvas.width = dpr * structure.canvas.width;
10514
+ canvas.height = dpr * structure.canvas.height;
10515
+ ctx.scale(dpr, dpr);
10516
+ const availableWidth = structure.canvas.width - CHART_PADDING$1 * 2;
10460
10517
  ctx.fillStyle = structure.canvas.backgroundColor;
10461
10518
  ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
10462
10519
  if (structure.title) {
@@ -10819,7 +10876,7 @@ class ScorecardChart extends Component {
10819
10876
  useEffect(this.createChart.bind(this), () => {
10820
10877
  const canvas = this.canvas.el;
10821
10878
  const rect = canvas.getBoundingClientRect();
10822
- return [rect.width, rect.height, this.runtime, this.canvas.el];
10879
+ return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
10823
10880
  });
10824
10881
  }
10825
10882
  createChart() {
@@ -18335,7 +18392,7 @@ const IF = {
18335
18392
  return { value: "" };
18336
18393
  }
18337
18394
  if (result.value === null) {
18338
- result.value = "";
18395
+ return { ...result, value: "" };
18339
18396
  }
18340
18397
  return result;
18341
18398
  },
@@ -18356,7 +18413,7 @@ const IFERROR = {
18356
18413
  return { value: "" };
18357
18414
  }
18358
18415
  if (result.value === null) {
18359
- result.value = "";
18416
+ return { ...result, value: "" };
18360
18417
  }
18361
18418
  return result;
18362
18419
  },
@@ -18377,7 +18434,7 @@ const IFNA = {
18377
18434
  return { value: "" };
18378
18435
  }
18379
18436
  if (result.value === null) {
18380
- result.value = "";
18437
+ return { ...result, value: "" };
18381
18438
  }
18382
18439
  return result;
18383
18440
  },
@@ -18403,7 +18460,7 @@ const IFS = {
18403
18460
  return { value: "" };
18404
18461
  }
18405
18462
  if (result.value === null) {
18406
- result.value = "";
18463
+ return { ...result, value: "" };
18407
18464
  }
18408
18465
  return result;
18409
18466
  }
@@ -18521,6 +18578,11 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
18521
18578
  if (range === undefined || range.invalidXc || range.invalidSheetName) {
18522
18579
  throw new InvalidReferenceError();
18523
18580
  }
18581
+ if (evalContext.__originCellPosition &&
18582
+ range.sheetId === evalContext.__originSheetId &&
18583
+ isZoneInside(positionToZone(evalContext.__originCellPosition), zone)) {
18584
+ throw new CircularDependencyError();
18585
+ }
18524
18586
  dependencies.push(range);
18525
18587
  }
18526
18588
  for (const measure of forMeasures) {
@@ -22408,9 +22470,11 @@ const GAUGE_INFLECTION_LABEL_BOTTOM_MARGIN = 6;
22408
22470
  const GAUGE_TITLE_SECTION_HEIGHT = 25;
22409
22471
  function drawGaugeChart(canvas, runtime) {
22410
22472
  const canvasBoundingRect = canvas.getBoundingClientRect();
22411
- canvas.width = canvasBoundingRect.width;
22412
- canvas.height = canvasBoundingRect.height;
22473
+ const dpr = window.devicePixelRatio || 1;
22474
+ canvas.width = dpr * canvasBoundingRect.width;
22475
+ canvas.height = dpr * canvasBoundingRect.height;
22413
22476
  const ctx = canvas.getContext("2d");
22477
+ ctx.scale(dpr, dpr);
22414
22478
  const config = getGaugeRenderingConfig(canvasBoundingRect, runtime, ctx);
22415
22479
  drawBackground(ctx, config);
22416
22480
  drawGauge(ctx, config);
@@ -22745,7 +22809,7 @@ class GaugeChartComponent extends Component {
22745
22809
  useEffect(() => drawGaugeChart(this.canvas.el, this.runtime), () => {
22746
22810
  const canvas = this.canvas.el;
22747
22811
  const rect = canvas.getBoundingClientRect();
22748
- return [rect.width, rect.height, this.runtime, this.canvas.el];
22812
+ return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
22749
22813
  });
22750
22814
  }
22751
22815
  }
@@ -22780,6 +22844,7 @@ const CHART_COMMON_OPTIONS = {
22780
22844
  },
22781
22845
  },
22782
22846
  animation: false,
22847
+ events: ["mousemove", "mouseout", "click", "touchstart", "touchmove", "mouseup"],
22783
22848
  };
22784
22849
  function truncateLabel(label) {
22785
22850
  if (!label) {
@@ -22805,8 +22870,7 @@ function chartToImage(runtime, figure, type) {
22805
22870
  if ("chartJsConfig" in runtime) {
22806
22871
  const config = deepCopy(runtime.chartJsConfig);
22807
22872
  config.plugins = [backgroundColorChartJSPlugin];
22808
- const Chart = getChartJSConstructor();
22809
- const chart = new Chart(canvas, config);
22873
+ const chart = new window.Chart(canvas, config);
22810
22874
  const imgContent = chart.toBase64Image();
22811
22875
  chart.destroy();
22812
22876
  div.remove();
@@ -27938,6 +28002,7 @@ function repairInitialMessages(data, initialMessages) {
27938
28002
  initialMessages = dropCommands(initialMessages, "SORT_CELLS");
27939
28003
  initialMessages = dropCommands(initialMessages, "SET_DECIMAL");
27940
28004
  initialMessages = fixChartDefinitions(data, initialMessages);
28005
+ initialMessages = fixTranslatedDuplicateSheetName(data, initialMessages);
27941
28006
  return initialMessages;
27942
28007
  }
27943
28008
  /**
@@ -28037,6 +28102,40 @@ function fixChartDefinitions(data, initialMessages) {
28037
28102
  }
28038
28103
  return messages;
28039
28104
  }
28105
+ function fixTranslatedDuplicateSheetName(data, initialMessages) {
28106
+ const sheetNames = {};
28107
+ for (const sheet of data.sheets || []) {
28108
+ sheetNames[sheet.id] = sheet.name;
28109
+ }
28110
+ const messages = [];
28111
+ for (const message of initialMessages) {
28112
+ if (message.type === "REMOTE_REVISION") {
28113
+ const commands = [];
28114
+ for (const cmd of message.commands) {
28115
+ switch (cmd.type) {
28116
+ case "DUPLICATE_SHEET":
28117
+ cmd.sheetNameTo =
28118
+ cmd.sheetNameTo ??
28119
+ getDuplicateSheetName(sheetNames[cmd.sheetId], Object.values(sheetNames));
28120
+ break;
28121
+ case "CREATE_SHEET":
28122
+ case "RENAME_SHEET":
28123
+ sheetNames[cmd.sheetId] = cmd.name || getNextSheetName(Object.values(sheetNames));
28124
+ break;
28125
+ }
28126
+ commands.push(cmd);
28127
+ }
28128
+ messages.push({
28129
+ ...message,
28130
+ commands,
28131
+ });
28132
+ }
28133
+ else {
28134
+ messages.push(message);
28135
+ }
28136
+ }
28137
+ return initialMessages;
28138
+ }
28040
28139
  // -----------------------------------------------------------------------------
28041
28140
  // Helpers
28042
28141
  // -----------------------------------------------------------------------------
@@ -28834,12 +28933,11 @@ function canBeLinearChart(definition, dataSets, labelRange, getters) {
28834
28933
  }
28835
28934
  let missingTimeAdapterAlreadyWarned = false;
28836
28935
  function isLuxonTimeAdapterInstalled() {
28837
- const Chart = getChartJSConstructor();
28838
- if (!Chart) {
28936
+ if (!window.Chart) {
28839
28937
  return false;
28840
28938
  }
28841
28939
  // @ts-ignore
28842
- const adapter = new Chart._adapters._date({});
28940
+ const adapter = new window.Chart._adapters._date({});
28843
28941
  const isInstalled = adapter._id === "luxon";
28844
28942
  if (!isInstalled && !missingTimeAdapterAlreadyWarned) {
28845
28943
  missingTimeAdapterAlreadyWarned = true;
@@ -29477,6 +29575,9 @@ const INTERACTIVE_LEGEND_CONFIG = {
29477
29575
  target.style.cursor = "default";
29478
29576
  },
29479
29577
  onClick: (event, legendItem, legend) => {
29578
+ if (event.type !== "click") {
29579
+ return;
29580
+ }
29480
29581
  const index = legendItem.datasetIndex;
29481
29582
  if (!legend.legendItems || index === undefined) {
29482
29583
  return;
@@ -29557,7 +29658,7 @@ function getBarChartScales(definition, args) {
29557
29658
  };
29558
29659
  scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29559
29660
  ...scales.x,
29560
- offset: false,
29661
+ offset: true,
29561
29662
  display: false,
29562
29663
  };
29563
29664
  }
@@ -30154,9 +30255,6 @@ class BarChart extends AbstractChart {
30154
30255
  };
30155
30256
  }
30156
30257
  getDefinitionForExcel() {
30157
- // Excel does not support aggregating labels
30158
- if (this.aggregated)
30159
- return undefined;
30160
30258
  const dataSets = this.dataSets
30161
30259
  .map((ds) => toExcelDataset(this.getters, ds))
30162
30260
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -30837,9 +30935,6 @@ class LineChart extends AbstractChart {
30837
30935
  return new LineChart(definition, this.sheetId, this.getters);
30838
30936
  }
30839
30937
  getDefinitionForExcel() {
30840
- // Excel does not support aggregating labels
30841
- if (this.aggregated)
30842
- return undefined;
30843
30938
  const dataSets = this.dataSets
30844
30939
  .map((ds) => toExcelDataset(this.getters, ds))
30845
30940
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -30976,9 +31071,6 @@ class PieChart extends AbstractChart {
30976
31071
  return new PieChart(definition, sheetId, this.getters);
30977
31072
  }
30978
31073
  getDefinitionForExcel() {
30979
- // Excel does not support aggregating labels
30980
- if (this.aggregated)
30981
- return undefined;
30982
31074
  const dataSets = this.dataSets
30983
31075
  .map((ds) => toExcelDataset(this.getters, ds))
30984
31076
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -33211,10 +33303,13 @@ const duplicateSheet = {
33211
33303
  name: _t("Duplicate"),
33212
33304
  execute: (env) => {
33213
33305
  const sheetIdFrom = env.model.getters.getActiveSheetId();
33306
+ const sheetNameFrom = env.model.getters.getSheetName(sheetIdFrom);
33214
33307
  const sheetIdTo = env.model.uuidGenerator.smallUuid();
33308
+ const sheetNameTo = env.model.getters.getDuplicateSheetName(sheetNameFrom);
33215
33309
  env.model.dispatch("DUPLICATE_SHEET", {
33216
33310
  sheetId: sheetIdFrom,
33217
33311
  sheetIdTo,
33312
+ sheetNameTo,
33218
33313
  });
33219
33314
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
33220
33315
  },
@@ -33454,18 +33549,28 @@ function isCtrlKey(ev) {
33454
33549
  function useInterval(callback, delay) {
33455
33550
  let intervalId;
33456
33551
  const { setInterval, clearInterval } = window;
33552
+ const pause = () => {
33553
+ clearInterval(intervalId);
33554
+ intervalId = undefined;
33555
+ };
33556
+ const safeCallback = () => {
33557
+ try {
33558
+ callback();
33559
+ }
33560
+ catch (e) {
33561
+ pause();
33562
+ throw e;
33563
+ }
33564
+ };
33457
33565
  useEffect(() => {
33458
- intervalId = setInterval(callback, delay);
33566
+ intervalId = setInterval(safeCallback, delay);
33459
33567
  return () => clearInterval(intervalId);
33460
33568
  }, () => [delay]);
33461
33569
  return {
33462
- pause: () => {
33463
- clearInterval(intervalId);
33464
- intervalId = undefined;
33465
- },
33570
+ pause,
33466
33571
  resume: () => {
33467
33572
  if (intervalId === undefined) {
33468
- intervalId = setInterval(callback, delay);
33573
+ intervalId = setInterval(safeCallback, delay);
33469
33574
  }
33470
33575
  },
33471
33576
  };
@@ -41024,6 +41129,13 @@ class Composer extends Component {
41024
41129
  openAssistant() {
41025
41130
  this.assistant.forcedClosed = false;
41026
41131
  }
41132
+ onWheel(event) {
41133
+ // detect if scrollbar is available
41134
+ if (this.composerRef.el &&
41135
+ this.composerRef.el.scrollHeight > this.composerRef.el.clientHeight) {
41136
+ event.stopPropagation();
41137
+ }
41138
+ }
41027
41139
  // ---------------------------------------------------------------------------
41028
41140
  // Private
41029
41141
  // ---------------------------------------------------------------------------
@@ -45961,8 +46073,8 @@ function compareDimensionValues(dimension, a, b) {
45961
46073
 
45962
46074
  const NULL_SYMBOL = Symbol("NULL");
45963
46075
  function createDate(dimension, value, locale) {
45964
- const granularity = dimension.granularity;
45965
- if (!granularity || !(granularity in MAP_VALUE_DIMENSION_DATE)) {
46076
+ const granularity = dimension.granularity || "month";
46077
+ if (!(granularity in MAP_VALUE_DIMENSION_DATE)) {
45966
46078
  throw new Error(`Unknown date granularity: ${granularity}`);
45967
46079
  }
45968
46080
  const keyInMap = typeof value === "number" || typeof value === "string" ? value : NULL_SYMBOL;
@@ -45981,6 +46093,9 @@ function createDate(dimension, value, locale) {
45981
46093
  case "month_number":
45982
46094
  number = date.getMonth() + 1;
45983
46095
  break;
46096
+ case "month":
46097
+ number = Math.floor(toNumber(value, locale));
46098
+ break;
45984
46099
  case "iso_week_number":
45985
46100
  number = date.getIsoWeek();
45986
46101
  break;
@@ -46074,6 +46189,10 @@ const MAP_VALUE_DIMENSION_DATE = {
46074
46189
  set: new Set(),
46075
46190
  values: {},
46076
46191
  },
46192
+ month: {
46193
+ set: new Set(),
46194
+ values: {},
46195
+ },
46077
46196
  iso_week_number: {
46078
46197
  set: new Set(),
46079
46198
  values: {},
@@ -46284,7 +46403,7 @@ class SpreadsheetPivot {
46284
46403
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
46285
46404
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
46286
46405
  if (dimension.type === "datetime") {
46287
- const adapter = pivotTimeAdapter(dimension.granularity);
46406
+ const adapter = pivotTimeAdapter((dimension.granularity || "month"));
46288
46407
  return adapter.toValueAndFormat(lastNode.value, this.getters.getLocale());
46289
46408
  }
46290
46409
  if (!finalCell) {
@@ -46402,7 +46521,7 @@ class SpreadsheetPivot {
46402
46521
  if (nonEmptyCells.length === 0) {
46403
46522
  return "integer";
46404
46523
  }
46405
- if (nonEmptyCells.every((cell) => cell.format && isDateTimeFormat(cell.format))) {
46524
+ if (nonEmptyCells.every((cell) => cell.type === CellValueType.number && cell.format && isDateTimeFormat(cell.format))) {
46406
46525
  return "datetime";
46407
46526
  }
46408
46527
  if (nonEmptyCells.every((cell) => cell.type === CellValueType.boolean)) {
@@ -46497,7 +46616,7 @@ class SpreadsheetPivot {
46497
46616
  for (const entry of dataEntries) {
46498
46617
  for (const dimension of dateDimensions) {
46499
46618
  const value = createDate(dimension, entry[dimension.fieldName]?.value || null, this.getters.getLocale());
46500
- const adapter = pivotTimeAdapter(dimension.granularity);
46619
+ const adapter = pivotTimeAdapter((dimension.granularity || "month"));
46501
46620
  const { format, value: valueToFormat } = adapter.toValueAndFormat(value, locale);
46502
46621
  entry[dimension.nameWithGranularity] = {
46503
46622
  value,
@@ -46517,6 +46636,7 @@ const dateGranularities = [
46517
46636
  "year",
46518
46637
  "quarter_number",
46519
46638
  "month_number",
46639
+ "month",
46520
46640
  "iso_week_number",
46521
46641
  "day_of_month",
46522
46642
  "day",
@@ -46764,7 +46884,7 @@ class PivotSidePanelStore extends SpreadsheetStore {
46764
46884
  : this.datetimeGranularities);
46765
46885
  }
46766
46886
  for (const field of dateFields) {
46767
- granularitiesPerFields[field.fieldName].delete(field.granularity);
46887
+ granularitiesPerFields[field.fieldName].delete(field.granularity || "month");
46768
46888
  }
46769
46889
  return granularitiesPerFields;
46770
46890
  }
@@ -48939,6 +49059,8 @@ class GridComposer extends Component {
48939
49059
  }
48940
49060
  get composerProps() {
48941
49061
  const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
49062
+ // Remove the wrapper border width
49063
+ const maxHeight = this.props.gridDims.height - this.rect.y - 2 * COMPOSER_BORDER_WIDTH;
48942
49064
  return {
48943
49065
  rect: { ...this.rect },
48944
49066
  delimitation: {
@@ -48956,6 +49078,7 @@ class GridComposer extends Component {
48956
49078
  }),
48957
49079
  onInputContextMenu: this.props.onInputContextMenu,
48958
49080
  composerStore: this.composerStore,
49081
+ inputStyle: `max-height: ${maxHeight}px;`,
48959
49082
  };
48960
49083
  }
48961
49084
  get containerStyle() {
@@ -50454,7 +50577,7 @@ css /* scss */ `
50454
50577
  position: absolute;
50455
50578
  top: 0;
50456
50579
  left: ${HEADER_WIDTH}px;
50457
- right: 0;
50580
+ right: ${SCROLLBAR_WIDTH}px;
50458
50581
  height: ${HEADER_HEIGHT}px;
50459
50582
  &.o-dragging {
50460
50583
  cursor: grabbing;
@@ -50620,9 +50743,8 @@ css /* scss */ `
50620
50743
  position: absolute;
50621
50744
  top: ${HEADER_HEIGHT}px;
50622
50745
  left: 0;
50623
- right: 0;
50746
+ bottom: ${SCROLLBAR_WIDTH}px;
50624
50747
  width: ${HEADER_WIDTH}px;
50625
- height: calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px);
50626
50748
  &.o-dragging {
50627
50749
  cursor: grabbing;
50628
50750
  }
@@ -54247,9 +54369,7 @@ class ChartPlugin extends CorePlugin {
54247
54369
  : "Success" /* CommandResult.Success */;
54248
54370
  }
54249
54371
  checkChartExists(cmd) {
54250
- return this.getters.getFigureSheetId(cmd.id)
54251
- ? "Success" /* CommandResult.Success */
54252
- : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
54372
+ return this.isChartDefined(cmd.id) ? "Success" /* CommandResult.Success */ : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
54253
54373
  }
54254
54374
  }
54255
54375
 
@@ -56534,6 +56654,7 @@ class SheetPlugin extends CorePlugin {
56534
56654
  "getCommandZones",
56535
56655
  "getUnboundedZone",
56536
56656
  "checkElementsIncludeAllNonFrozenHeaders",
56657
+ "getDuplicateSheetName",
56537
56658
  ];
56538
56659
  sheetIdsMapName = {};
56539
56660
  orderedSheetIds = [];
@@ -56558,7 +56679,11 @@ class SheetPlugin extends CorePlugin {
56558
56679
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
56559
56680
  }
56560
56681
  case "DUPLICATE_SHEET": {
56561
- return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
56682
+ if (this.sheets[cmd.sheetIdTo])
56683
+ return "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */;
56684
+ if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo))
56685
+ return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
56686
+ return "Success" /* CommandResult.Success */;
56562
56687
  }
56563
56688
  case "MOVE_SHEET":
56564
56689
  try {
@@ -56635,7 +56760,7 @@ class SheetPlugin extends CorePlugin {
56635
56760
  this.showSheet(cmd.sheetId);
56636
56761
  break;
56637
56762
  case "DUPLICATE_SHEET":
56638
- this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo);
56763
+ this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo, cmd.sheetNameTo);
56639
56764
  break;
56640
56765
  case "DELETE_SHEET":
56641
56766
  this.deleteSheet(this.sheets[cmd.sheetId]);
@@ -56841,14 +56966,8 @@ class SheetPlugin extends CorePlugin {
56841
56966
  return dimension === "COL" ? this.getNumberCols(sheetId) : this.getNumberRows(sheetId);
56842
56967
  }
56843
56968
  getNextSheetName(baseName = "Sheet") {
56844
- let i = 1;
56845
56969
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
56846
- let name = `${baseName}${i}`;
56847
- while (names.includes(name)) {
56848
- name = `${baseName}${i}`;
56849
- i++;
56850
- }
56851
- return name;
56970
+ return getNextSheetName(names, baseName);
56852
56971
  }
56853
56972
  getSheetSize(sheetId) {
56854
56973
  return {
@@ -57094,9 +57213,8 @@ class SheetPlugin extends CorePlugin {
57094
57213
  showSheet(sheetId) {
57095
57214
  this.history.update("sheets", sheetId, "isVisible", true);
57096
57215
  }
57097
- duplicateSheet(fromId, toId) {
57216
+ duplicateSheet(fromId, toId, toName) {
57098
57217
  const sheet = this.getSheet(fromId);
57099
- const toName = this.getDuplicateSheetName(sheet.name);
57100
57218
  const newSheet = deepCopy(sheet);
57101
57219
  newSheet.id = toId;
57102
57220
  newSheet.name = toName;
@@ -57128,15 +57246,8 @@ class SheetPlugin extends CorePlugin {
57128
57246
  this.history.update("sheetIdsMapName", sheetIdsMapName);
57129
57247
  }
57130
57248
  getDuplicateSheetName(sheetName) {
57131
- let i = 1;
57132
57249
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
57133
- const baseName = _t("Copy of %s", sheetName);
57134
- let name = baseName.toString();
57135
- while (names.includes(name)) {
57136
- name = `${baseName} (${i})`;
57137
- i++;
57138
- }
57139
- return name;
57250
+ return getDuplicateSheetName(sheetName, names);
57140
57251
  }
57141
57252
  deleteSheet(sheet) {
57142
57253
  const name = sheet.name;
@@ -58623,6 +58734,15 @@ function adaptPivotRange(range, applyChange) {
58623
58734
  }
58624
58735
  }
58625
58736
  class SpreadsheetPivotCorePlugin extends CorePlugin {
58737
+ allowDispatch(cmd) {
58738
+ switch (cmd.type) {
58739
+ case "ADD_PIVOT":
58740
+ case "UPDATE_PIVOT":
58741
+ const definition = cmd.pivot;
58742
+ return this.checkDataSetValidity(definition);
58743
+ }
58744
+ return "Success" /* CommandResult.Success */;
58745
+ }
58626
58746
  adaptRanges(applyChange) {
58627
58747
  for (const pivotId of this.getters.getPivotIds()) {
58628
58748
  const definition = this.getters.getPivotCoreDefinition(pivotId);
@@ -58641,6 +58761,16 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
58641
58761
  }
58642
58762
  }
58643
58763
  }
58764
+ checkDataSetValidity(definition) {
58765
+ if (definition.type === "SPREADSHEET" && definition.dataSet) {
58766
+ const { zone, sheetId } = definition.dataSet;
58767
+ if (!sheetId || !this.getters.tryGetSheet(sheetId) || !zone || !isZoneValid(zone)) {
58768
+ return "InvalidDataSet" /* CommandResult.InvalidDataSet */;
58769
+ }
58770
+ return this.getters.checkZonesExistInSheet(sheetId, [zone]);
58771
+ }
58772
+ return "Success" /* CommandResult.Success */;
58773
+ }
58644
58774
  }
58645
58775
 
58646
58776
  class TableStylePlugin extends CorePlugin {
@@ -59944,8 +60074,8 @@ class SpreadingRelation {
59944
60074
  const EMPTY_ARRAY = [];
59945
60075
 
59946
60076
  const MAX_ITERATION = 30;
59947
- const ERROR_CYCLE_CELL = createEvaluatedCell(new CircularDependencyError());
59948
- const EMPTY_CELL = createEvaluatedCell({ value: null });
60077
+ const ERROR_CYCLE_CELL = Object.freeze(createEvaluatedCell(new CircularDependencyError()));
60078
+ const EMPTY_CELL = Object.freeze(createEvaluatedCell({ value: null }));
59949
60079
  class Evaluator {
59950
60080
  context;
59951
60081
  getters;
@@ -61440,7 +61570,7 @@ class DynamicTablesPlugin extends UIPlugin {
61440
61570
  tables = {};
61441
61571
  handle(cmd) {
61442
61572
  if (invalidateEvaluationCommands.has(cmd.type) ||
61443
- (cmd.type === "UPDATE_CELL" && "content" in cmd) ||
61573
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd)) ||
61444
61574
  cmd.type === "EVALUATE_CELLS") {
61445
61575
  this.tables = {};
61446
61576
  return;
@@ -65297,7 +65427,7 @@ class TableComputedStylePlugin extends UIPlugin {
65297
65427
  tableStyles = {};
65298
65428
  handle(cmd) {
65299
65429
  if (invalidateEvaluationCommands.has(cmd.type) ||
65300
- (cmd.type === "UPDATE_CELL" && "content" in cmd) ||
65430
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd)) ||
65301
65431
  cmd.type === "EVALUATE_CELLS") {
65302
65432
  this.tableStyles = {};
65303
65433
  return;
@@ -67261,6 +67391,8 @@ class GridSelectionPlugin extends UIPlugin {
67261
67391
  });
67262
67392
  this.selectCell(col, row);
67263
67393
  }
67394
+ const { col, row } = this.gridSelection.anchor.cell;
67395
+ this.moveClient({ sheetId: this.activeSheet.id, col, row });
67264
67396
  }
67265
67397
  /**
67266
67398
  * Ensure selections are not outside sheet boundaries.
@@ -68000,8 +68132,11 @@ class SheetViewPlugin extends UIPlugin {
68000
68132
  case "REMOVE_TABLE":
68001
68133
  case "UPDATE_TABLE":
68002
68134
  case "UPDATE_FILTER":
68003
- this.sheetsWithDirtyViewports.add(cmd.sheetId);
68004
- break;
68135
+ case "UNFREEZE_ROWS":
68136
+ case "UNFREEZE_COLUMNS":
68137
+ case "FREEZE_COLUMNS":
68138
+ case "FREEZE_ROWS":
68139
+ case "UNFREEZE_COLUMNS_ROWS":
68005
68140
  case "REMOVE_COLUMNS_ROWS":
68006
68141
  case "RESIZE_COLUMNS_ROWS":
68007
68142
  case "HIDE_COLUMNS_ROWS":
@@ -68014,11 +68149,9 @@ class SheetViewPlugin extends UIPlugin {
68014
68149
  case "FOLD_HEADER_GROUPS_IN_ZONE":
68015
68150
  case "UNFOLD_HEADER_GROUPS_IN_ZONE":
68016
68151
  case "UNFOLD_ALL_HEADER_GROUPS":
68017
- case "FOLD_ALL_HEADER_GROUPS": {
68018
- const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.getActiveSheetId();
68019
- this.sheetsWithDirtyViewports.add(sheetId);
68152
+ case "FOLD_ALL_HEADER_GROUPS":
68153
+ this.sheetsWithDirtyViewports.add(cmd.sheetId);
68020
68154
  break;
68021
- }
68022
68155
  case "UPDATE_CELL":
68023
68156
  // update cell content or format can change hidden rows because of data filters
68024
68157
  if ("content" in cmd || "format" in cmd || cmd.style?.fontSize !== undefined) {
@@ -68034,13 +68167,6 @@ class SheetViewPlugin extends UIPlugin {
68034
68167
  case "ACTIVATE_SHEET":
68035
68168
  this.sheetsWithDirtyViewports.add(cmd.sheetIdTo);
68036
68169
  break;
68037
- case "UNFREEZE_ROWS":
68038
- case "UNFREEZE_COLUMNS":
68039
- case "FREEZE_COLUMNS":
68040
- case "FREEZE_ROWS":
68041
- case "UNFREEZE_COLUMNS_ROWS":
68042
- this.resetViewports(this.getters.getActiveSheetId());
68043
- break;
68044
68170
  case "SCROLL_TO_CELL":
68045
68171
  this.refreshViewport(this.getters.getActiveSheetId(), { col: cmd.col, row: cmd.row });
68046
68172
  break;
@@ -69218,7 +69344,7 @@ class AggregateStatisticsStore extends SpreadsheetStore {
69218
69344
  }
69219
69345
  handle(cmd) {
69220
69346
  if (invalidateEvaluationCommands.has(cmd.type) ||
69221
- (cmd.type === "UPDATE_CELL" && "content" in cmd)) {
69347
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd))) {
69222
69348
  this.isDirty = true;
69223
69349
  }
69224
69350
  switch (cmd.type) {
@@ -71281,11 +71407,13 @@ class Spreadsheet extends Component {
71281
71407
  this.checkViewportSize();
71282
71408
  stores.on("store-updated", this, render);
71283
71409
  resizeObserver.observe(this.spreadsheetRef.el);
71410
+ registerChartJSExtensions();
71284
71411
  });
71285
71412
  onWillUnmount(() => {
71286
71413
  this.unbindModelEvents();
71287
71414
  stores.off("store-updated", this);
71288
71415
  resizeObserver.disconnect();
71416
+ unregisterChartJsExtensions();
71289
71417
  });
71290
71418
  onPatched(() => {
71291
71419
  this.checkViewportSize();
@@ -75735,6 +75863,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
75735
75863
  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 };
75736
75864
 
75737
75865
 
75738
- __info__.version = "18.1.17";
75739
- __info__.date = "2025-04-25T08:08:46.599Z";
75740
- __info__.hash = "a63687f";
75866
+ __info__.version = "18.1.19";
75867
+ __info__.date = "2025-05-12T05:26:05.861Z";
75868
+ __info__.hash = "44cc170";