@odoo/o-spreadsheet 17.2.2 → 17.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.2
7
- * @date 2024-04-05T14:01:19.824Z
8
- * @hash c15836d
6
+ * @version 17.2.4
7
+ * @date 2024-04-18T16:41:38.407Z
8
+ * @hash 0c66038
9
9
  */
10
10
 
11
11
  import { reactive, useEnv, useSubEnv, useState, onWillUnmount, markRaw, toRaw, Component, useRef, onMounted, useEffect, onPatched, useComponent, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv } from '@odoo/owl';
@@ -560,7 +560,7 @@ function deepEquals(o1, o2) {
560
560
  if (typeof o1 !== typeof o2)
561
561
  return false;
562
562
  if (typeof o1 !== "object")
563
- return o1 === o2;
563
+ return false;
564
564
  // Objects can have different keys if the values are undefined
565
565
  for (const key in o2) {
566
566
  if (!(key in o1) && o2[key] !== undefined) {
@@ -2507,6 +2507,15 @@ function matrixMap(matrix, fn) {
2507
2507
  }
2508
2508
  return generateMatrix(matrix.length, matrix[0].length, (col, row) => fn(matrix[col][row]));
2509
2509
  }
2510
+ function matrixForEach(matrix, fn) {
2511
+ const numberOfCols = matrix.length;
2512
+ const numberOfRows = matrix[0]?.length ?? 0;
2513
+ for (let col = 0; col < numberOfCols; col++) {
2514
+ for (let row = 0; row < numberOfRows; row++) {
2515
+ fn(matrix[col][row]);
2516
+ }
2517
+ }
2518
+ }
2510
2519
  function transposeMatrix(matrix) {
2511
2520
  if (!matrix.length) {
2512
2521
  return [];
@@ -18634,7 +18643,7 @@ class FunctionRegistry extends Registry {
18634
18643
  }
18635
18644
  const descr = addMetaInfoFromArg(addDescr);
18636
18645
  validateArguments(descr.args);
18637
- this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr)), name);
18646
+ this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr), name), name);
18638
18647
  super.add(name, descr);
18639
18648
  return this;
18640
18649
  }
@@ -18673,9 +18682,7 @@ function handleError(e, functionName) {
18673
18682
  // so we fallback to a generic error
18674
18683
  if (hasStringValue(e) && isEvaluationError(e.value)) {
18675
18684
  if (hasStringMessage(e)) {
18676
- if (e.message?.includes("[[FUNCTION_NAME]]")) {
18677
- e.message = e.message.replace("[[FUNCTION_NAME]]", functionName);
18678
- }
18685
+ replaceFunctionNamePlaceholder(e, functionName);
18679
18686
  }
18680
18687
  return e;
18681
18688
  }
@@ -18690,21 +18697,29 @@ function hasStringMessage(obj) {
18690
18697
  return (obj?.message !== undefined &&
18691
18698
  typeof obj.message === "string");
18692
18699
  }
18693
- function addResultHandling(compute) {
18694
- return function (...args) {
18700
+ function addResultHandling(compute, functionName) {
18701
+ return function computeWithResultHandling(...args) {
18695
18702
  const result = compute.apply(this, args);
18696
18703
  if (!isMatrix(result)) {
18697
18704
  if (typeof result === "object" && result !== null && "value" in result) {
18705
+ replaceFunctionNamePlaceholder(result, functionName);
18698
18706
  return result;
18699
18707
  }
18700
18708
  return { value: result };
18701
18709
  }
18702
18710
  if (typeof result[0][0] === "object" && result[0][0] !== null && "value" in result[0][0]) {
18711
+ matrixForEach(result, (result) => replaceFunctionNamePlaceholder(result, functionName));
18703
18712
  return result;
18704
18713
  }
18705
18714
  return matrixMap(result, (row) => ({ value: row }));
18706
18715
  };
18707
18716
  }
18717
+ function replaceFunctionNamePlaceholder(fPayload, functionName) {
18718
+ // for performance reasons: change in place and only if needed
18719
+ if (fPayload.message?.includes("[[FUNCTION_NAME]]")) {
18720
+ fPayload.message = fPayload.message.replace("[[FUNCTION_NAME]]", functionName);
18721
+ }
18722
+ }
18708
18723
  const functionRegistry = new FunctionRegistry();
18709
18724
  for (let category of categories) {
18710
18725
  const fns = category.functions;
@@ -19472,7 +19487,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale })
19472
19487
  const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
19473
19488
  // tooltipItem.parsed.y can be an object or a number for pie charts
19474
19489
  const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
19475
- const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
19490
+ const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
19476
19491
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
19477
19492
  return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
19478
19493
  },
@@ -19772,7 +19787,10 @@ function getBarConfiguration(chart, labels, localeFormat) {
19772
19787
  if (isNaN(value))
19773
19788
  return value;
19774
19789
  const { locale, format } = localeFormat;
19775
- return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
19790
+ return formatValue(value, {
19791
+ locale,
19792
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
19793
+ });
19776
19794
  },
19777
19795
  },
19778
19796
  },
@@ -20293,7 +20311,10 @@ function getLineOrScatterConfiguration(chart, labels, localeFormat) {
20293
20311
  if (isNaN(value))
20294
20312
  return value;
20295
20313
  const { locale, format } = localeFormat;
20296
- return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
20314
+ return formatValue(value, {
20315
+ locale,
20316
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
20317
+ });
20297
20318
  },
20298
20319
  },
20299
20320
  },
@@ -20633,7 +20654,7 @@ function getPieConfiguration(chart, labels, localeFormat) {
20633
20654
  const percentage = calculatePercentage(data, dataIndex);
20634
20655
  const xLabel = tooltipItem.label || tooltipItem.dataset.label;
20635
20656
  const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
20636
- const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
20657
+ const toolTipFormat = !format && yLabel >= 1000 ? "#,##" : format;
20637
20658
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
20638
20659
  return xLabel ? `${xLabel}: ${yLabelStr} (${percentage}%)` : `${yLabelStr} (${percentage}%)`;
20639
20660
  };
@@ -22885,6 +22906,7 @@ class LinkEditor extends Component {
22885
22906
  this.save();
22886
22907
  }
22887
22908
  ev.stopPropagation();
22909
+ ev.preventDefault();
22888
22910
  break;
22889
22911
  case "Escape":
22890
22912
  this.cancel();
@@ -31967,6 +31989,7 @@ class Composer extends Component {
31967
31989
  onComposerCellFocused: { type: Function, optional: true },
31968
31990
  onComposerContentFocused: Function,
31969
31991
  isDefaultFocus: { type: Boolean, optional: true },
31992
+ onInputContextMenu: { type: Function, optional: true },
31970
31993
  };
31971
31994
  static components = { TextValueProvider, FunctionDescriptionProvider };
31972
31995
  static defaultProps = {
@@ -32017,6 +32040,9 @@ class Composer extends Component {
32017
32040
  assistantStyle.right = `0px`;
32018
32041
  }
32019
32042
  }
32043
+ else if (this.props.delimitation) {
32044
+ assistantStyle["max-height"] = `${this.props.delimitation.height}px`;
32045
+ }
32020
32046
  return cssPropertiesToCss(assistantStyle);
32021
32047
  }
32022
32048
  // we can't allow input events to be triggered while we remove and add back the content of the composer in processContent
@@ -32303,6 +32329,11 @@ class Composer extends Component {
32303
32329
  }
32304
32330
  }
32305
32331
  }
32332
+ onContextMenu(ev) {
32333
+ if (this.composerStore.editionMode === "inactive") {
32334
+ this.props.onInputContextMenu?.(ev);
32335
+ }
32336
+ }
32306
32337
  // ---------------------------------------------------------------------------
32307
32338
  // Private
32308
32339
  // ---------------------------------------------------------------------------
@@ -32524,6 +32555,7 @@ class GridComposer extends Component {
32524
32555
  static template = "o-spreadsheet-GridComposer";
32525
32556
  static props = {
32526
32557
  gridDims: Object,
32558
+ onInputContextMenu: Function,
32527
32559
  };
32528
32560
  static components = { Composer };
32529
32561
  rect = this.defaultRect;
@@ -32571,6 +32603,7 @@ class GridComposer extends Component {
32571
32603
  isDefaultFocus: true,
32572
32604
  onComposerContentFocused: () => this.composerFocusStore.focusGridComposerContent(),
32573
32605
  onComposerCellFocused: (content) => this.composerFocusStore.focusGridComposerCell(content),
32606
+ onInputContextMenu: this.props.onInputContextMenu,
32574
32607
  };
32575
32608
  }
32576
32609
  get containerStyle() {
@@ -33150,6 +33183,10 @@ css /*SCSS*/ `
33150
33183
  height: 0px;
33151
33184
  }
33152
33185
  }
33186
+ .o-figure-container {
33187
+ -webkit-user-select: none; // safari
33188
+ user-select: none;
33189
+ }
33153
33190
  `;
33154
33191
  /**
33155
33192
  * Each figure ⭐ is positioned inside a container `div` placed and sized
@@ -37293,29 +37330,12 @@ function convertWidthFromExcel(width) {
37293
37330
  return width;
37294
37331
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
37295
37332
  }
37296
- function convertBorderDescr(descr) {
37297
- if (!descr) {
37298
- return undefined;
37299
- }
37300
- return {
37301
- style: descr.style,
37302
- color: { rgb: descr.color },
37303
- };
37304
- }
37305
37333
  function extractStyle(cell, data) {
37306
37334
  let style = {};
37307
37335
  if (cell.style) {
37308
37336
  style = data.styles[cell.style];
37309
37337
  }
37310
37338
  const format = extractFormat(cell, data);
37311
- const exportedBorder = {};
37312
- if (cell.border) {
37313
- const border = data.borders[cell.border];
37314
- exportedBorder.left = convertBorderDescr(border.left);
37315
- exportedBorder.right = convertBorderDescr(border.right);
37316
- exportedBorder.bottom = convertBorderDescr(border.bottom);
37317
- exportedBorder.top = convertBorderDescr(border.top);
37318
- }
37319
37339
  const styles = {
37320
37340
  font: {
37321
37341
  size: style?.fontSize || DEFAULT_FONT_SIZE,
@@ -37329,7 +37349,7 @@ function extractStyle(cell, data) {
37329
37349
  }
37330
37350
  : { reservedAttribute: "none" },
37331
37351
  numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
37332
- border: exportedBorder || {},
37352
+ border: cell.border || 0,
37333
37353
  alignment: {
37334
37354
  horizontal: style.align,
37335
37355
  vertical: style.verticalAlign
@@ -37351,15 +37371,12 @@ function extractFormat(cell, data) {
37351
37371
  return undefined;
37352
37372
  }
37353
37373
  function normalizeStyle(construct, styles) {
37354
- const { id: fontId } = pushElement(styles["font"], construct.fonts);
37355
- const { id: fillId } = pushElement(styles["fill"], construct.fills);
37356
- const { id: borderId } = pushElement(styles["border"], construct.borders);
37357
37374
  // Normalize this
37358
37375
  const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
37359
37376
  const style = {
37360
- fontId,
37361
- fillId,
37362
- borderId,
37377
+ fontId: pushElement(styles.font, construct.fonts),
37378
+ fillId: pushElement(styles.fill, construct.fills),
37379
+ borderId: styles.border,
37363
37380
  numFmtId,
37364
37381
  alignment: {
37365
37382
  vertical: styles.alignment.vertical,
@@ -37367,8 +37384,7 @@ function normalizeStyle(construct, styles) {
37367
37384
  wrapText: styles.alignment.wrapText,
37368
37385
  },
37369
37386
  };
37370
- const { id } = pushElement(style, construct.styles);
37371
- return id;
37387
+ return pushElement(style, construct.styles);
37372
37388
  }
37373
37389
  function convertFormat(format, numFmtStructure) {
37374
37390
  if (!format) {
@@ -37376,8 +37392,7 @@ function convertFormat(format, numFmtStructure) {
37376
37392
  }
37377
37393
  let formatId = XLSX_FORMAT_MAP[format.format];
37378
37394
  if (!formatId) {
37379
- const { id } = pushElement(format, numFmtStructure);
37380
- formatId = id + FIRST_NUMFMT_ID;
37395
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
37381
37396
  }
37382
37397
  return formatId;
37383
37398
  }
@@ -37402,20 +37417,15 @@ function addRelsToFile(relsFiles, path, rel) {
37402
37417
  return id;
37403
37418
  }
37404
37419
  function pushElement(property, propertyList) {
37405
- for (let [key, value] of Object.entries(propertyList)) {
37406
- if (JSON.stringify(value) === JSON.stringify(property)) {
37407
- return { id: parseInt(key, 10), list: propertyList };
37420
+ let len = propertyList.length;
37421
+ const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
37422
+ for (let i = 0; i < len; i++) {
37423
+ if (operator(property, propertyList[i])) {
37424
+ return i;
37408
37425
  }
37409
37426
  }
37410
- let elemId = propertyList.findIndex((elem) => JSON.stringify(elem) === JSON.stringify(property));
37411
- if (elemId === -1) {
37412
- propertyList.push(property);
37413
- elemId = propertyList.length - 1;
37414
- }
37415
- return {
37416
- id: elemId,
37417
- list: propertyList,
37418
- };
37427
+ propertyList[propertyList.length] = property;
37428
+ return propertyList.length - 1;
37419
37429
  }
37420
37430
  const chartIds = [];
37421
37431
  /**
@@ -38210,7 +38220,25 @@ function parseXML(xmlString, mimeType = "text/xml") {
38210
38220
  }
38211
38221
  return document;
38212
38222
  }
38213
- function getDefaultXLSXStructure() {
38223
+ function convertBorderDescr(descr) {
38224
+ if (!descr) {
38225
+ return undefined;
38226
+ }
38227
+ return {
38228
+ style: descr.style,
38229
+ color: { rgb: descr.color },
38230
+ };
38231
+ }
38232
+ function getDefaultXLSXStructure(data) {
38233
+ const xlsxBorders = Object.values(data.borders).map((border) => {
38234
+ return {
38235
+ left: convertBorderDescr(border.left),
38236
+ right: convertBorderDescr(border.right),
38237
+ bottom: convertBorderDescr(border.bottom),
38238
+ top: convertBorderDescr(border.top),
38239
+ };
38240
+ });
38241
+ const borders = [{}, ...xlsxBorders];
38214
38242
  return {
38215
38243
  relsFiles: [],
38216
38244
  sharedStrings: [],
@@ -38233,7 +38261,7 @@ function getDefaultXLSXStructure() {
38233
38261
  },
38234
38262
  ],
38235
38263
  fills: [{ reservedAttribute: "none" }, { reservedAttribute: "gray125" }],
38236
- borders: [{}],
38264
+ borders,
38237
38265
  numFmts: [],
38238
38266
  dxfs: [],
38239
38267
  };
@@ -45270,7 +45298,15 @@ class TablePlugin extends CorePlugin {
45270
45298
  }
45271
45299
  }
45272
45300
  exportForExcel(data) {
45273
- this.export(data);
45301
+ for (const sheet of data.sheets) {
45302
+ for (const table of this.getTables(sheet.id)) {
45303
+ if (zoneToDimension(table.range.zone).numberOfRows === 1) {
45304
+ continue;
45305
+ }
45306
+ const tableData = { range: zoneToXc(table.range.zone), filters: [] };
45307
+ sheet.tables.push(tableData);
45308
+ }
45309
+ }
45274
45310
  }
45275
45311
  }
45276
45312
 
@@ -47042,7 +47078,9 @@ class Evaluator {
47042
47078
  this.blockedArrayFormulas = this.createEmptyPositionSet();
47043
47079
  this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
47044
47080
  this.formulaDependencies = lazy(() => {
47045
- const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position).map((range) => ({
47081
+ const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
47082
+ .filter((range) => !range.invalidSheetName && !range.invalidXc)
47083
+ .map((range) => ({
47046
47084
  data: position,
47047
47085
  boundingBox: {
47048
47086
  zone: range.zone,
@@ -52072,7 +52110,7 @@ class FilterEvaluationPlugin extends UIPlugin {
52072
52110
  "isFilterActive",
52073
52111
  ];
52074
52112
  filterValues = {};
52075
- hiddenRows = new Set();
52113
+ hiddenRows = {};
52076
52114
  isEvaluationDirty = false;
52077
52115
  allowDispatch(cmd) {
52078
52116
  switch (cmd.type) {
@@ -52116,11 +52154,11 @@ class FilterEvaluationPlugin extends UIPlugin {
52116
52154
  case "UNFOLD_HEADER_GROUP":
52117
52155
  case "FOLD_ALL_HEADER_GROUPS":
52118
52156
  case "UNFOLD_ALL_HEADER_GROUPS":
52119
- this.updateHiddenRows();
52157
+ this.updateHiddenRows(cmd.sheetId);
52120
52158
  break;
52121
52159
  case "UPDATE_FILTER":
52122
52160
  this.updateFilter(cmd);
52123
- this.updateHiddenRows();
52161
+ this.updateHiddenRows(cmd.sheetId);
52124
52162
  break;
52125
52163
  case "DUPLICATE_SHEET":
52126
52164
  const filterValues = {};
@@ -52140,15 +52178,14 @@ class FilterEvaluationPlugin extends UIPlugin {
52140
52178
  }
52141
52179
  finalize() {
52142
52180
  if (this.isEvaluationDirty) {
52143
- this.updateHiddenRows();
52181
+ for (const sheetId of this.getters.getSheetIds()) {
52182
+ this.updateHiddenRows(sheetId);
52183
+ }
52144
52184
  this.isEvaluationDirty = false;
52145
52185
  }
52146
52186
  }
52147
52187
  isRowFiltered(sheetId, row) {
52148
- if (sheetId !== this.getters.getActiveSheetId()) {
52149
- return false;
52150
- }
52151
- return this.hiddenRows.has(row);
52188
+ return !!this.hiddenRows[sheetId]?.has(row);
52152
52189
  }
52153
52190
  getFilterHiddenValues(position) {
52154
52191
  const id = this.getters.getFilterId(position);
@@ -52175,8 +52212,7 @@ class FilterEvaluationPlugin extends UIPlugin {
52175
52212
  this.filterValues[sheetId] = {};
52176
52213
  this.filterValues[sheetId][id] = hiddenValues;
52177
52214
  }
52178
- updateHiddenRows() {
52179
- const sheetId = this.getters.getActiveSheetId();
52215
+ updateHiddenRows(sheetId) {
52180
52216
  const filters = this.getters
52181
52217
  .getFilters(sheetId)
52182
52218
  .sort((filter1, filter2) => filter1.rangeWithHeaders.zone.top - filter2.rangeWithHeaders.zone.top);
@@ -52198,7 +52234,7 @@ class FilterEvaluationPlugin extends UIPlugin {
52198
52234
  }
52199
52235
  }
52200
52236
  }
52201
- this.hiddenRows = hiddenRows;
52237
+ this.hiddenRows[sheetId] = hiddenRows;
52202
52238
  }
52203
52239
  getCellValueAsString(sheetId, col, row) {
52204
52240
  const value = this.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue;
@@ -53317,13 +53353,14 @@ class SheetViewPlugin extends UIPlugin {
53317
53353
  }
53318
53354
  }
53319
53355
  handleEvent(event) {
53356
+ const sheetId = this.getters.getActiveSheetId();
53320
53357
  if (event.options.scrollIntoView) {
53321
53358
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
53322
53359
  if (event.mode === "updateAnchor") {
53323
53360
  const oldZone = event.previousAnchor.zone;
53324
53361
  const newZone = event.anchor.zone;
53325
53362
  // altering a zone should not move the viewport in a dimension that wasn't changed
53326
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
53363
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
53327
53364
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
53328
53365
  col = left > col || col > right ? left : col;
53329
53366
  }
@@ -53331,7 +53368,6 @@ class SheetViewPlugin extends UIPlugin {
53331
53368
  row = top > row || row > bottom ? top : row;
53332
53369
  }
53333
53370
  }
53334
- const sheetId = this.getters.getActiveSheetId();
53335
53371
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
53336
53372
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
53337
53373
  if (!this.sheetsWithDirtyViewports.has(sheetId)) {
@@ -53368,16 +53404,16 @@ class SheetViewPlugin extends UIPlugin {
53368
53404
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
53369
53405
  break;
53370
53406
  case "SHIFT_VIEWPORT_DOWN":
53371
- const { top } = this.getActiveMainViewport();
53372
53407
  const sheetId = this.getters.getActiveSheetId();
53373
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
53374
- this.shiftVertically(shiftedOffsetY);
53408
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
53409
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
53410
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
53375
53411
  break;
53376
53412
  case "SHIFT_VIEWPORT_UP": {
53377
- const { top } = this.getActiveMainViewport();
53378
53413
  const sheetId = this.getters.getActiveSheetId();
53379
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
53380
- this.shiftVertically(shiftedOffsetY);
53414
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
53415
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
53416
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
53381
53417
  break;
53382
53418
  }
53383
53419
  case "REMOVE_TABLE":
@@ -53800,17 +53836,6 @@ class SheetViewPlugin extends UIPlugin {
53800
53836
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
53801
53837
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
53802
53838
  }
53803
- /**
53804
- * Clip the vertical offset within the allowed range.
53805
- * Not above the sheet, nor below the sheet.
53806
- */
53807
- clipOffsetY(offsetY) {
53808
- const { height } = this.getMainViewportRect();
53809
- const maxOffset = height - this.sheetViewHeight;
53810
- offsetY = Math.min(offsetY, maxOffset);
53811
- offsetY = Math.max(offsetY, 0);
53812
- return offsetY;
53813
- }
53814
53839
  getViewportOffset(sheetId) {
53815
53840
  return {
53816
53841
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -53866,12 +53891,15 @@ class SheetViewPlugin extends UIPlugin {
53866
53891
  * viewport top.
53867
53892
  */
53868
53893
  shiftVertically(offset) {
53869
- const { top } = this.getActiveMainViewport();
53894
+ const sheetId = this.getters.getActiveSheetId();
53895
+ const { top } = this.getMainInternalViewport(sheetId);
53870
53896
  const { scrollX } = this.getActiveSheetScrollInfo();
53871
53897
  this.setSheetViewOffset(scrollX, offset);
53872
53898
  const { anchor } = this.getters.getSelection();
53873
- const deltaRow = this.getActiveMainViewport().top - top;
53874
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
53899
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
53900
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
53901
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
53902
+ }
53875
53903
  }
53876
53904
  getVisibleFigures() {
53877
53905
  const sheetId = this.getters.getActiveSheetId();
@@ -54790,7 +54818,6 @@ css /* scss */ `
54790
54818
  cursor: pointer;
54791
54819
  }
54792
54820
  `;
54793
- let tKey = 1;
54794
54821
  class SpreadsheetDashboard extends Component {
54795
54822
  static template = "o-spreadsheet-SpreadsheetDashboard";
54796
54823
  static props = {};
@@ -54869,13 +54896,9 @@ class SpreadsheetDashboard extends Component {
54869
54896
  coordinates: rect,
54870
54897
  position: { col, row },
54871
54898
  action,
54872
- // we can't rely on position only because a row or a column could
54873
- // be inserted at any time.
54874
- tKey: `${tKey}-${col}-${row}`,
54875
54899
  });
54876
54900
  }
54877
54901
  }
54878
- tKey++;
54879
54902
  return cells;
54880
54903
  }
54881
54904
  getClickableAction(position) {
@@ -55687,6 +55710,13 @@ class TopBarComposer extends Component {
55687
55710
  "border-color": SELECTION_BORDER_COLOR,
55688
55711
  });
55689
55712
  }
55713
+ get delimitation() {
55714
+ const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
55715
+ return {
55716
+ width,
55717
+ height,
55718
+ };
55719
+ }
55690
55720
  onFocus(selection) {
55691
55721
  this.composerFocusStore.focusTopBarComposer(selection);
55692
55722
  }
@@ -58318,8 +58348,7 @@ function addContent(content, sharedStrings, forceString = false) {
58318
58348
  attrs.push(["t", "b"]);
58319
58349
  }
58320
58350
  else if (forceString || !isNumber(value, DEFAULT_LOCALE)) {
58321
- const { id } = pushElement(content, sharedStrings);
58322
- value = id.toString();
58351
+ value = pushElement(content, sharedStrings);
58323
58352
  attrs.push(["t", "s"]);
58324
58353
  }
58325
58354
  return { attrs, node: escapeXml /*xml*/ `<v>${value}</v>` };
@@ -58444,8 +58473,7 @@ function addCellIsRule(cf, rule, dxfs) {
58444
58473
  if (rule.style.fillColor) {
58445
58474
  dxf.fill = { fgColor: { rgb: rule.style.fillColor } };
58446
58475
  }
58447
- const { id } = pushElement(dxf, dxfs);
58448
- ruleAttributes.push(["dxfId", id]);
58476
+ ruleAttributes.push(["dxfId", pushElement(dxf, dxfs)]);
58449
58477
  return escapeXml /*xml*/ `
58450
58478
  <conditionalFormatting sqref="${cf.ranges.join(" ")}">
58451
58479
  <cfRule ${formatAttributes(ruleAttributes)}>
@@ -59275,7 +59303,7 @@ function addSheetViews(sheet) {
59275
59303
  */
59276
59304
  function getXLSX(data) {
59277
59305
  const files = [];
59278
- const construct = getDefaultXLSXStructure();
59306
+ const construct = getDefaultXLSXStructure(data);
59279
59307
  files.push(createWorkbook(data, construct));
59280
59308
  files.push(...createWorksheets(data, construct));
59281
59309
  files.push(createStylesSheet(construct));
@@ -60169,6 +60197,6 @@ const constants = {
60169
60197
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, 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 };
60170
60198
 
60171
60199
 
60172
- __info__.version = "17.2.2";
60173
- __info__.date = "2024-04-05T14:01:19.824Z";
60174
- __info__.hash = "c15836d";
60200
+ __info__.version = "17.2.4";
60201
+ __info__.date = "2024-04-18T16:41:38.407Z";
60202
+ __info__.hash = "0c66038";