@odoo/o-spreadsheet 18.3.6 → 18.3.8

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.3.6
6
- * @date 2025-05-30T08:46:25.817Z
7
- * @hash afa4379
5
+ * @version 18.3.8
6
+ * @date 2025-06-12T09:51:55.929Z
7
+ * @hash 32dedd1
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -5880,7 +5880,9 @@ function isTextFormat(format) {
5880
5880
  }
5881
5881
 
5882
5882
  function evaluateLiteral(literalCell, localeFormat) {
5883
- const value = isTextFormat(localeFormat.format) ? literalCell.content : literalCell.parsedValue;
5883
+ const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
5884
+ ? literalCell.content
5885
+ : literalCell.parsedValue;
5884
5886
  const functionResult = { value, format: localeFormat.format };
5885
5887
  return createEvaluatedCell(functionResult, localeFormat.locale);
5886
5888
  }
@@ -5929,6 +5931,9 @@ function _createEvaluatedCell(functionResult, locale, cell) {
5929
5931
  if (isEvaluationError(value)) {
5930
5932
  return errorCell(value, message);
5931
5933
  }
5934
+ if (value === null) {
5935
+ return emptyCell(format);
5936
+ }
5932
5937
  if (isTextFormat(format)) {
5933
5938
  // TO DO:
5934
5939
  // with the next line, the value of the cell is transformed depending on the format.
@@ -5936,9 +5941,6 @@ function _createEvaluatedCell(functionResult, locale, cell) {
5936
5941
  // to interpret the value as a number.
5937
5942
  return textCell(toString(value), format, formattedValue);
5938
5943
  }
5939
- if (value === null) {
5940
- return emptyCell(format);
5941
- }
5942
5944
  if (typeof value === "number") {
5943
5945
  if (isDateTimeFormat(format || "")) {
5944
5946
  return dateTimeCell(value, format, formattedValue);
@@ -20955,8 +20957,6 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
20955
20957
  if (isNaN(value)) {
20956
20958
  continue;
20957
20959
  }
20958
- const axisId = chart.config.type === "radar" ? dataset.rAxisID : dataset.yAxisID;
20959
- const displayValue = options.callback(Number(value), axisId);
20960
20960
  const point = dataset.data[i];
20961
20961
  const xPosition = point.x;
20962
20962
  let yPosition = 0;
@@ -20980,7 +20980,8 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
20980
20980
  textsPositions[xPosition].push(yPosition);
20981
20981
  ctx.fillStyle = point.options.backgroundColor;
20982
20982
  ctx.strokeStyle = options.background || "#ffffff";
20983
- drawTextWithBackground(displayValue, xPosition, yPosition, ctx);
20983
+ const valueToDisplay = options.callback(Number(value), dataset, i);
20984
+ drawTextWithBackground(valueToDisplay, xPosition, yPosition, ctx);
20984
20985
  }
20985
20986
  }
20986
20987
  }
@@ -20997,7 +20998,7 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
20997
20998
  if (isNaN(value)) {
20998
20999
  continue;
20999
21000
  }
21000
- const displayValue = options.callback(value, dataset.xAxisID);
21001
+ const displayValue = options.callback(value, dataset, i);
21001
21002
  const point = dataset.data[i];
21002
21003
  const yPosition = point.y;
21003
21004
  let xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
@@ -21032,10 +21033,22 @@ function drawPieChartValues(chart, options, ctx) {
21032
21033
  const midAngle = (startAngle + endAngle) / 2;
21033
21034
  const midRadius = (innerRadius + outerRadius) / 2;
21034
21035
  const x = bar.x + midRadius * Math.cos(midAngle);
21035
- const y = bar.y + midRadius * Math.sin(midAngle) + 7;
21036
+ const y = bar.y + midRadius * Math.sin(midAngle);
21037
+ const displayValue = options.callback(value, dataset, i);
21038
+ const textHeight = 12; // ChartJS default
21039
+ const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
21040
+ const radius = outerRadius - innerRadius;
21041
+ // Check if the text fits in the slice. Not perfect, but good enough heuristic.
21042
+ if (textWidth >= radius || radius < textHeight) {
21043
+ continue;
21044
+ }
21045
+ const sliceAngle = endAngle - startAngle;
21046
+ const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
21047
+ if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
21048
+ continue;
21049
+ }
21036
21050
  ctx.fillStyle = chartFontColor(options.background);
21037
21051
  ctx.strokeStyle = options.background || "#ffffff";
21038
- const displayValue = options.callback(value, "y");
21039
21052
  drawTextWithBackground(displayValue, x, y, ctx);
21040
21053
  }
21041
21054
  }
@@ -26356,7 +26369,10 @@ function getChartShowValues(definition, args) {
26356
26369
  horizontal: "horizontal" in definition && definition.horizontal,
26357
26370
  showValues: "showValues" in definition ? !!definition.showValues : false,
26358
26371
  background: definition.background,
26359
- callback: formatChartDatasetValue(axisFormats, locale),
26372
+ callback: (value, dataset) => {
26373
+ const axisId = getDatasetAxisId(definition, dataset);
26374
+ return formatChartDatasetValue(axisFormats, locale)(value, axisId);
26375
+ },
26360
26376
  };
26361
26377
  }
26362
26378
  function getSunburstShowValues(definition, args) {
@@ -26374,6 +26390,45 @@ function getSunburstShowValues(definition, args) {
26374
26390
  },
26375
26391
  };
26376
26392
  }
26393
+ function getPyramidChartShowValues(definition, args) {
26394
+ const { axisFormats, locale } = args;
26395
+ return {
26396
+ horizontal: true,
26397
+ showValues: "showValues" in definition ? !!definition.showValues : false,
26398
+ background: definition.background,
26399
+ callback: (value, dataset) => {
26400
+ value = Math.abs(Number(value));
26401
+ return formatChartDatasetValue(axisFormats, locale)(value, dataset.xAxisID || "x");
26402
+ },
26403
+ };
26404
+ }
26405
+ function getWaterfallChartShowValues(definition, args) {
26406
+ const { axisFormats, locale, dataSetsValues } = args;
26407
+ const subtotalIndexes = dataSetsValues.reduce((subtotalIndexes, ds) => {
26408
+ subtotalIndexes.push((subtotalIndexes.at(-1) || -1) + ds.data.length + 1);
26409
+ return subtotalIndexes;
26410
+ }, []);
26411
+ return {
26412
+ showValues: "showValues" in definition ? !!definition.showValues : false,
26413
+ background: definition.background,
26414
+ callback: (value, dataset, index) => {
26415
+ const raw = dataset._dataset.data[index];
26416
+ const delta = raw[1] - raw[0];
26417
+ let sign = delta >= 0 ? "+" : "";
26418
+ if (definition.showSubTotals && subtotalIndexes.includes(index) && sign === "+") {
26419
+ sign = "";
26420
+ }
26421
+ return `${sign}${formatChartDatasetValue(axisFormats, locale)(delta, dataset.yAxisID)}`;
26422
+ },
26423
+ };
26424
+ }
26425
+ function getDatasetAxisId(definition, dataset) {
26426
+ if (dataset.rAxisID) {
26427
+ return dataset.rAxisID;
26428
+ }
26429
+ const axisId = "horizontal" in definition && definition.horizontal ? dataset.xAxisID : dataset.yAxisID;
26430
+ return axisId || "y";
26431
+ }
26377
26432
 
26378
26433
  function getChartTitle(definition) {
26379
26434
  const chartTitle = definition.title;
@@ -26776,6 +26831,7 @@ var CHART_RUNTIME_HELPERS = /*#__PURE__*/Object.freeze({
26776
26831
  getPieChartTooltip: getPieChartTooltip,
26777
26832
  getPyramidChartData: getPyramidChartData,
26778
26833
  getPyramidChartScales: getPyramidChartScales,
26834
+ getPyramidChartShowValues: getPyramidChartShowValues,
26779
26835
  getPyramidChartTooltip: getPyramidChartTooltip,
26780
26836
  getRadarChartData: getRadarChartData,
26781
26837
  getRadarChartDatasets: getRadarChartDatasets,
@@ -26795,6 +26851,7 @@ var CHART_RUNTIME_HELPERS = /*#__PURE__*/Object.freeze({
26795
26851
  getTrendDatasetForLineChart: getTrendDatasetForLineChart,
26796
26852
  getWaterfallChartLegend: getWaterfallChartLegend,
26797
26853
  getWaterfallChartScales: getWaterfallChartScales,
26854
+ getWaterfallChartShowValues: getWaterfallChartShowValues,
26798
26855
  getWaterfallChartTooltip: getWaterfallChartTooltip,
26799
26856
  getWaterfallDatasetAndLabels: getWaterfallDatasetAndLabels,
26800
26857
  makeDatasetsCumulative: makeDatasetsCumulative
@@ -28074,7 +28131,7 @@ function createPyramidChartRuntime(chart, getters) {
28074
28131
  title: getChartTitle(definition),
28075
28132
  legend: getBarChartLegend(definition),
28076
28133
  tooltip: getPyramidChartTooltip(definition, chartData),
28077
- chartShowValuesPlugin: getChartShowValues(definition, chartData),
28134
+ chartShowValuesPlugin: getPyramidChartShowValues(definition, chartData),
28078
28135
  },
28079
28136
  },
28080
28137
  };
@@ -28815,7 +28872,7 @@ function createWaterfallChartRuntime(chart, getters) {
28815
28872
  title: getChartTitle(definition),
28816
28873
  legend: getWaterfallChartLegend(definition),
28817
28874
  tooltip: getWaterfallChartTooltip(definition, chartData),
28818
- chartShowValuesPlugin: getChartShowValues(definition, chartData),
28875
+ chartShowValuesPlugin: getWaterfallChartShowValues(definition, chartData),
28819
28876
  waterfallLinesPlugin: { showConnectorLines: definition.showConnectorLines },
28820
28877
  },
28821
28878
  },
@@ -33127,7 +33184,7 @@ class XlsxBaseExtractor {
33127
33184
  */
33128
33185
  handleMissingValue(parentElement, missingElementName, optionalArgs) {
33129
33186
  if (optionalArgs?.required) {
33130
- if (optionalArgs?.default) {
33187
+ if (optionalArgs?.default !== undefined) {
33131
33188
  this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
33132
33189
  }
33133
33190
  else {
@@ -36080,19 +36137,26 @@ class FilterMenu extends Component {
36080
36137
  .filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
36081
36138
  .map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
36082
36139
  const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
36083
- const strValues = [...cellValues, ...filterValues];
36084
- const normalizedFilteredValues = filterValues.map(toLowerCase);
36085
- // Set with lowercase values to avoid duplicates
36086
- const normalizedValues = [...new Set(strValues.map(toLowerCase))];
36087
- const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
36088
- return sortedValues.map((normalizedValue) => {
36089
- const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
36090
- -1;
36091
- return {
36092
- checked,
36093
- string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
36094
- };
36095
- });
36140
+ const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
36141
+ const set = new Set();
36142
+ const values = [];
36143
+ const addValue = (value) => {
36144
+ const normalizedValue = toLowerCase(value);
36145
+ if (!set.has(normalizedValue)) {
36146
+ values.push({
36147
+ string: value || "",
36148
+ checked: !normalizedFilteredValues.has(normalizedValue),
36149
+ normalizedValue,
36150
+ });
36151
+ set.add(normalizedValue);
36152
+ }
36153
+ };
36154
+ cellValues.forEach(addValue);
36155
+ filterValues.forEach(addValue);
36156
+ return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
36157
+ numeric: true,
36158
+ sensitivity: "base",
36159
+ }));
36096
36160
  }
36097
36161
  checkValue(value) {
36098
36162
  this.state.selectedValue = value.string;
@@ -47367,13 +47431,15 @@ class FindAndReplaceStore extends SpreadsheetStore {
47367
47431
  if (this.selectedMatchIndex === null) {
47368
47432
  return;
47369
47433
  }
47434
+ this.preserveSelectedMatchIndex = true;
47435
+ this.shouldFinalizeUpdateSelection = true;
47370
47436
  this.model.dispatch("REPLACE_SEARCH", {
47371
47437
  searchString: this.toSearch,
47372
47438
  replaceWith: this.toReplace,
47373
47439
  matches: [this.searchMatches[this.selectedMatchIndex]],
47374
47440
  searchOptions: this.searchOptions,
47375
47441
  });
47376
- this.selectNextCell(Direction.next, { jumpToMatchSheet: true, updateSelection: true });
47442
+ this.preserveSelectedMatchIndex = false;
47377
47443
  }
47378
47444
  /**
47379
47445
  * Apply the replace function to all the matches one time.
@@ -53529,7 +53595,7 @@ class HoveredTableStore extends SpreadsheetStore {
53529
53595
  }
53530
53596
  }
53531
53597
  hover(position) {
53532
- if (position.col === this.col && position.row === this.row) {
53598
+ if (!this.getters.isDashboard() || (position.col === this.col && position.row === this.row)) {
53533
53599
  return "noStateChange";
53534
53600
  }
53535
53601
  this.col = position.col;
@@ -55205,6 +55271,9 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
55205
55271
  let deltaX = lastX - clientX;
55206
55272
  let deltaY = lastY - clientY;
55207
55273
  const elapsedTime = currentTime - lastTime;
55274
+ if (!elapsedTime) {
55275
+ return;
55276
+ }
55208
55277
  velocityX = deltaX / elapsedTime;
55209
55278
  velocityY = deltaY / elapsedTime;
55210
55279
  lastX = clientX;
@@ -55225,6 +55294,11 @@ function useTouchScroll(ref, updateScroll, canMoveUp) {
55225
55294
  function onTouchEnd(ev) {
55226
55295
  isMouseDown = false;
55227
55296
  lastX = lastY = 0;
55297
+ if (resetTimeout) {
55298
+ clearTimeout(resetTimeout);
55299
+ }
55300
+ velocityX *= 1.2;
55301
+ velocityY *= 1.2;
55228
55302
  requestAnimationFrame(scroll);
55229
55303
  }
55230
55304
  function scroll() {
@@ -61423,7 +61497,9 @@ class TablePlugin extends CorePlugin {
61423
61497
  const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
61424
61498
  const union = this.getters.getRangesUnion(ranges);
61425
61499
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
61426
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
61500
+ if (mergesInTarget.length) {
61501
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
61502
+ }
61427
61503
  const id = this.consumeNextId();
61428
61504
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
61429
61505
  const newTable = cmd.tableType === "dynamic"
@@ -61522,14 +61598,16 @@ class TablePlugin extends CorePlugin {
61522
61598
  const zoneToCheckIfEmpty = direction === "down"
61523
61599
  ? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
61524
61600
  : { ...zone, right: zone.right + 1, left: zone.right + 1 };
61525
- for (const position of positions(zoneToCheckIfEmpty)) {
61526
- const cellPosition = { sheetId, ...position };
61527
- // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
61528
- const cellContent = this.getters.getCell(cellPosition)?.content;
61529
- if (cellContent ||
61530
- this.getters.isInMerge(cellPosition) ||
61531
- this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
61532
- return "none";
61601
+ for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
61602
+ for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
61603
+ const cellPosition = { sheetId, col, row };
61604
+ // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
61605
+ const cellContent = this.getters.getCell(cellPosition)?.content;
61606
+ if (cellContent ||
61607
+ this.getters.isInMerge(cellPosition) ||
61608
+ this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
61609
+ return "none";
61610
+ }
61533
61611
  }
61534
61612
  }
61535
61613
  return direction;
@@ -62315,7 +62393,7 @@ class PivotCorePlugin extends CorePlugin {
62315
62393
  break;
62316
62394
  }
62317
62395
  case "UPDATE_PIVOT": {
62318
- this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
62396
+ this.history.update("pivots", cmd.pivotId, "definition", this.repairSortedColumn(deepCopy(cmd.pivot)));
62319
62397
  this.compileCalculatedMeasures(cmd.pivot.measures);
62320
62398
  break;
62321
62399
  }
@@ -62386,7 +62464,10 @@ class PivotCorePlugin extends CorePlugin {
62386
62464
  // Private
62387
62465
  // -------------------------------------------------------------------------
62388
62466
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
62389
- this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
62467
+ this.history.update("pivots", pivotId, {
62468
+ definition: this.repairSortedColumn(deepCopy(pivot)),
62469
+ formulaId,
62470
+ });
62390
62471
  this.compileCalculatedMeasures(pivot.measures);
62391
62472
  this.history.update("formulaIds", formulaId, pivotId);
62392
62473
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
@@ -62475,6 +62556,7 @@ class PivotCorePlugin extends CorePlugin {
62475
62556
  }
62476
62557
  }
62477
62558
  checkSortedColumnInMeasures(definition) {
62559
+ definition = this.repairSortedColumn(definition);
62478
62560
  const measures = definition.measures.map((measure) => measure.id);
62479
62561
  if (definition.sortedColumn && !measures.includes(definition.sortedColumn.measure)) {
62480
62562
  return "InvalidDefinition" /* CommandResult.InvalidDefinition */;
@@ -62488,6 +62570,26 @@ class PivotCorePlugin extends CorePlugin {
62488
62570
  }
62489
62571
  return "Success" /* CommandResult.Success */;
62490
62572
  }
62573
+ repairSortedColumn(definition) {
62574
+ if (definition.sortedColumn) {
62575
+ // Fix for an upgrade issue: the sortedColumn measure was not updated
62576
+ // from using fieldName to using id. If the sortedColumn measure matches
62577
+ // a measure fieldName in the definition, update it to use the measure's id instead
62578
+ // of its fieldName.
62579
+ // TODO: add an upgrade step to fix this in master and remove this code
62580
+ const sortedMeasure = definition.measures.find((measure) => measure.fieldName === definition.sortedColumn?.measure);
62581
+ if (sortedMeasure) {
62582
+ return {
62583
+ ...definition,
62584
+ sortedColumn: {
62585
+ ...definition.sortedColumn,
62586
+ measure: sortedMeasure.id,
62587
+ },
62588
+ };
62589
+ }
62590
+ }
62591
+ return definition;
62592
+ }
62491
62593
  // ---------------------------------------------------------------------
62492
62594
  // Import/Export
62493
62595
  // ---------------------------------------------------------------------
@@ -71131,9 +71233,10 @@ class FilterEvaluationPlugin extends UIPlugin {
71131
71233
  const filteredZone = filter.filteredRange?.zone;
71132
71234
  if (!filteredValues || !filteredZone)
71133
71235
  continue;
71236
+ const filteredValuesSet = new Set(filteredValues);
71134
71237
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
71135
71238
  const value = this.getCellValueAsString(sheetId, filter.col, row);
71136
- if (filteredValues.includes(value)) {
71239
+ if (filteredValuesSet.has(value)) {
71137
71240
  hiddenRows.add(row);
71138
71241
  }
71139
71242
  }
@@ -71647,11 +71750,6 @@ class GridSelectionPlugin extends UIPlugin {
71647
71750
  },
71648
71751
  ];
71649
71752
  const sheetId = this.getActiveSheetId();
71650
- const handler = new CellClipboardHandler(this.getters, this.dispatch);
71651
- const data = handler.copy(getClipboardDataPositions(sheetId, target));
71652
- if (!data) {
71653
- return;
71654
- }
71655
71753
  const base = isBasedBefore ? cmd.base : cmd.base + 1;
71656
71754
  const pasteTarget = [
71657
71755
  {
@@ -71661,7 +71759,14 @@ class GridSelectionPlugin extends UIPlugin {
71661
71759
  bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
71662
71760
  },
71663
71761
  ];
71664
- handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
71762
+ for (const Handler of clipboardHandlersRegistries.cellHandlers.getAll()) {
71763
+ const handler = new Handler(this.getters, this.dispatch);
71764
+ const data = handler.copy(getClipboardDataPositions(sheetId, target));
71765
+ if (!data) {
71766
+ continue;
71767
+ }
71768
+ handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
71769
+ }
71665
71770
  const selection = pasteTarget[0];
71666
71771
  const col = selection.left;
71667
71772
  const row = selection.top;
@@ -80515,6 +80620,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
80515
80620
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, 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, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
80516
80621
 
80517
80622
 
80518
- __info__.version = "18.3.6";
80519
- __info__.date = "2025-05-30T08:46:25.817Z";
80520
- __info__.hash = "afa4379";
80623
+ __info__.version = "18.3.8";
80624
+ __info__.date = "2025-06-12T09:51:55.929Z";
80625
+ __info__.hash = "32dedd1";