@odoo/o-spreadsheet 18.2.6 → 18.2.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.2.6
6
- * @date 2025-04-04T08:41:26.115Z
7
- * @hash faa00e2
5
+ * @version 18.2.8
6
+ * @date 2025-04-18T16:26:20.673Z
7
+ * @hash 5da9ddc
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';
@@ -3573,6 +3573,7 @@ const coreTypes = new Set([
3573
3573
  "CLEAR_FORMATTING",
3574
3574
  "SET_BORDER",
3575
3575
  "SET_ZONE_BORDERS",
3576
+ "SET_BORDERS_ON_TARGET",
3576
3577
  /** CHART */
3577
3578
  "CREATE_CHART",
3578
3579
  "UPDATE_CHART",
@@ -6722,6 +6723,7 @@ class AbstractCellClipboardHandler extends ClipboardHandler {
6722
6723
  }
6723
6724
 
6724
6725
  class BorderClipboardHandler extends AbstractCellClipboardHandler {
6726
+ queuedBordersToAdd = {};
6725
6727
  copy(data) {
6726
6728
  const sheetId = data.sheetId;
6727
6729
  if (data.zones.length === 0) {
@@ -6752,6 +6754,7 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
6752
6754
  const { left, top } = zones[0];
6753
6755
  this.pasteZone(sheetId, left, top, content.borders);
6754
6756
  }
6757
+ this.executeQueuedChanges(sheetId);
6755
6758
  }
6756
6759
  pasteZone(sheetId, col, row, borders) {
6757
6760
  for (const [r, rowBorders] of borders.entries()) {
@@ -6770,7 +6773,20 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
6770
6773
  ...targetBorders,
6771
6774
  ...originBorders,
6772
6775
  };
6773
- this.dispatch("SET_BORDER", { ...target, border });
6776
+ const borderKey = JSON.stringify(border);
6777
+ if (!this.queuedBordersToAdd[borderKey]) {
6778
+ this.queuedBordersToAdd[borderKey] = [];
6779
+ }
6780
+ this.queuedBordersToAdd[borderKey].push(positionToZone(target));
6781
+ }
6782
+ executeQueuedChanges(pasteSheetTarget) {
6783
+ for (const borderKey in this.queuedBordersToAdd) {
6784
+ const zones = this.queuedBordersToAdd[borderKey];
6785
+ const border = JSON.parse(borderKey);
6786
+ const target = recomputeZones(zones, []);
6787
+ this.dispatch("SET_BORDERS_ON_TARGET", { sheetId: pasteSheetTarget, target, border });
6788
+ }
6789
+ this.queuedBordersToAdd = {};
6774
6790
  }
6775
6791
  }
6776
6792
 
@@ -6882,6 +6898,12 @@ function tokenizeString(chars) {
6882
6898
  }
6883
6899
  return null;
6884
6900
  }
6901
+ /**
6902
+ - \p{L} is for any letter (from any language)
6903
+ - \p{N} is for any number
6904
+ - the u flag at the end is for unicode, which enables the `\p{...}` syntax
6905
+ */
6906
+ const unicodeSymbolCharRegexp = /\p{L}|\p{N}|_|\.|!|\$/u;
6885
6907
  const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
6886
6908
  /**
6887
6909
  * A "Symbol" is just basically any word-like element that can appear in a
@@ -6922,7 +6944,8 @@ function tokenizeSymbol(chars) {
6922
6944
  };
6923
6945
  }
6924
6946
  }
6925
- while (chars.current && SYMBOL_CHARS.has(chars.current)) {
6947
+ while (chars.current &&
6948
+ (SYMBOL_CHARS.has(chars.current) || chars.current.match(unicodeSymbolCharRegexp))) {
6926
6949
  result += chars.shift();
6927
6950
  }
6928
6951
  if (result.length) {
@@ -8710,12 +8733,13 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
8710
8733
  }
8711
8734
  pasteCf(origin, target, isCutOperation) {
8712
8735
  if (origin?.rules && origin.rules.length > 0) {
8736
+ const originZone = positionToZone(origin.position);
8713
8737
  const zone = positionToZone(target);
8714
8738
  for (const rule of origin.rules) {
8715
8739
  const toRemoveZones = [];
8716
8740
  if (isCutOperation) {
8717
8741
  //remove from current rule
8718
- toRemoveZones.push(positionToZone(origin.position));
8742
+ toRemoveZones.push(originZone);
8719
8743
  }
8720
8744
  if (origin.position.sheetId === target.sheetId) {
8721
8745
  this.adaptCFRules(origin.position.sheetId, rule, [zone], toRemoveZones);
@@ -8829,6 +8853,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
8829
8853
  pasteDataValidation(origin, target, isCutOperation) {
8830
8854
  if (origin) {
8831
8855
  const zone = positionToZone(target);
8856
+ const originZone = positionToZone(origin.position);
8832
8857
  const rule = origin.rule;
8833
8858
  if (!rule) {
8834
8859
  const targetRule = this.getters.getValidationRuleForCell(target);
@@ -8840,7 +8865,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
8840
8865
  }
8841
8866
  const toRemoveZone = [];
8842
8867
  if (isCutOperation) {
8843
- toRemoveZone.push(positionToZone(origin.position));
8868
+ toRemoveZone.push(originZone);
8844
8869
  }
8845
8870
  if (origin.position.sheetId === target.sheetId) {
8846
8871
  const copyToRule = this.getDataValidationRuleToCopyTo(target.sheetId, rule, false);
@@ -8900,7 +8925,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
8900
8925
  continue;
8901
8926
  }
8902
8927
  this.dispatch("ADD_DATA_VALIDATION_RULE", {
8903
- rule: dv,
8928
+ rule: { id: dv.id, criterion: dv.criterion, isBlocking: dv.isBlocking },
8904
8929
  ranges: newDvZones.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
8905
8930
  sheetId,
8906
8931
  });
@@ -9227,7 +9252,7 @@ function transformZone(zone, executed) {
9227
9252
  if (executed.type === "ADD_COLUMNS_ROWS") {
9228
9253
  return expandZoneOnInsertion(zone, executed.dimension === "COL" ? "left" : "top", executed.base, executed.position, executed.quantity);
9229
9254
  }
9230
- return { ...zone };
9255
+ return zone;
9231
9256
  }
9232
9257
  function transformRangeData(range, executed) {
9233
9258
  const deletedSheet = executed.type === "DELETE_SHEET" && executed.sheetId;
@@ -33618,6 +33643,12 @@ function isMacOS() {
33618
33643
  function isCtrlKey(ev) {
33619
33644
  return isMacOS() ? ev.metaKey : ev.ctrlKey;
33620
33645
  }
33646
+ /**
33647
+ * Detects if the current browser is Firefox
33648
+ */
33649
+ function isBrowserFirefox() {
33650
+ return /Firefox/i.test(navigator.userAgent);
33651
+ }
33621
33652
 
33622
33653
  /**
33623
33654
  * Repeatedly calls a callback function with a time delay between calls.
@@ -50413,39 +50444,6 @@ function useCellHovered(env, gridRef, callback) {
50413
50444
  }
50414
50445
  return hoveredPosition;
50415
50446
  }
50416
- function useTouchMove(gridRef, handler, canMoveUp) {
50417
- let x = null;
50418
- let y = null;
50419
- function onTouchStart(ev) {
50420
- if (ev.touches.length !== 1)
50421
- return;
50422
- x = ev.touches[0].clientX;
50423
- y = ev.touches[0].clientY;
50424
- }
50425
- function onTouchEnd() {
50426
- x = null;
50427
- y = null;
50428
- }
50429
- function onTouchMove(ev) {
50430
- if (ev.touches.length !== 1)
50431
- return;
50432
- // On mobile browsers, swiping down is often associated with "pull to refresh".
50433
- // We only want this behavior if the grid is already at the top.
50434
- // Otherwise we only want to move the canvas up, without triggering any refresh.
50435
- if (canMoveUp()) {
50436
- ev.preventDefault();
50437
- ev.stopPropagation();
50438
- }
50439
- const currentX = ev.touches[0].clientX;
50440
- const currentY = ev.touches[0].clientY;
50441
- handler(x - currentX, y - currentY);
50442
- x = currentX;
50443
- y = currentY;
50444
- }
50445
- useRefListener(gridRef, "touchstart", onTouchStart);
50446
- useRefListener(gridRef, "touchend", onTouchEnd);
50447
- useRefListener(gridRef, "touchmove", onTouchMove);
50448
- }
50449
50447
  class GridOverlay extends Component {
50450
50448
  static template = "o-spreadsheet-GridOverlay";
50451
50449
  static props = {
@@ -50493,10 +50491,6 @@ class GridOverlay extends Component {
50493
50491
  onWillUnmount(() => {
50494
50492
  resizeObserver.disconnect();
50495
50493
  });
50496
- useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
50497
- const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
50498
- return scrollY > 0;
50499
- });
50500
50494
  this.cellPopovers = useStore(CellPopoverStore);
50501
50495
  this.paintFormatStore = useStore(PaintFormatStore);
50502
50496
  }
@@ -51968,6 +51962,73 @@ function useGridDrawing(refName, model, canvasSize) {
51968
51962
  }
51969
51963
  }
51970
51964
 
51965
+ const friction = 0.95;
51966
+ const verticalScrollFactor = 1;
51967
+ const horizontalScrollFactor = 1;
51968
+ function useTouchScroll(ref, updateScroll, canMoveUp) {
51969
+ let lastX = 0;
51970
+ let lastY = 0;
51971
+ let velocityX = 0;
51972
+ let velocityY = 0;
51973
+ let isMouseDown = false;
51974
+ let lastTime = 0;
51975
+ useRefListener(ref, "touchstart", onTouchStart, { capture: false });
51976
+ useRefListener(ref, "touchmove", onTouchMove, { capture: false });
51977
+ useRefListener(ref, "touchend", onTouchEnd, { capture: false });
51978
+ function onTouchStart(event) {
51979
+ isMouseDown = true;
51980
+ ({ clientX: lastX, clientY: lastY } = event.touches[0]);
51981
+ velocityX = 0;
51982
+ velocityY = 0;
51983
+ }
51984
+ function onTouchMove(event) {
51985
+ if (!isMouseDown)
51986
+ return;
51987
+ const currentTime = Date.now();
51988
+ const { clientX, clientY } = event.touches[0];
51989
+ let deltaX = lastX - clientX;
51990
+ let deltaY = lastY - clientY;
51991
+ const elapsedTime = currentTime - lastTime;
51992
+ velocityX = deltaX / elapsedTime;
51993
+ velocityY = deltaY / elapsedTime;
51994
+ lastX = clientX;
51995
+ lastY = clientY;
51996
+ lastTime = currentTime;
51997
+ if (canMoveUp()) {
51998
+ if (event.cancelable) {
51999
+ event.preventDefault();
52000
+ }
52001
+ event.stopPropagation();
52002
+ }
52003
+ updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
52004
+ }
52005
+ function onTouchEnd(ev) {
52006
+ isMouseDown = false;
52007
+ lastX = lastY = 0;
52008
+ requestAnimationFrame(scroll);
52009
+ }
52010
+ function scroll() {
52011
+ if (Math.abs(velocityX) < 0.05) {
52012
+ velocityX = 0;
52013
+ }
52014
+ if (Math.abs(velocityY) < 0.05) {
52015
+ velocityY = 0;
52016
+ }
52017
+ if (!velocityX && !velocityY) {
52018
+ return;
52019
+ }
52020
+ const currentTime = Date.now();
52021
+ const elapsedTime = Math.abs(currentTime - lastTime);
52022
+ const deltaX = velocityX * elapsedTime;
52023
+ const deltaY = velocityY * elapsedTime;
52024
+ updateScroll(deltaX * horizontalScrollFactor, deltaY * verticalScrollFactor);
52025
+ lastTime = currentTime;
52026
+ velocityX *= friction;
52027
+ velocityY *= friction;
52028
+ requestAnimationFrame(scroll);
52029
+ }
52030
+ }
52031
+
51971
52032
  function useWheelHandler(handler) {
51972
52033
  function normalize(val, deltaMode) {
51973
52034
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
@@ -52308,7 +52369,7 @@ class HorizontalScrollBar extends Component {
52308
52369
  left: `${this.props.leftOffset + x}px`,
52309
52370
  bottom: "0px",
52310
52371
  height: `${SCROLLBAR_WIDTH}px`,
52311
- right: `0px`,
52372
+ right: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
52312
52373
  };
52313
52374
  }
52314
52375
  onScroll(offset) {
@@ -52353,7 +52414,7 @@ class VerticalScrollBar extends Component {
52353
52414
  top: `${this.props.topOffset + y}px`,
52354
52415
  right: "0px",
52355
52416
  width: `${SCROLLBAR_WIDTH}px`,
52356
- bottom: `0px`,
52417
+ bottom: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
52357
52418
  };
52358
52419
  }
52359
52420
  onScroll(offset) {
@@ -52589,6 +52650,10 @@ class Grid extends Component {
52589
52650
  this.DOMFocusableElementStore.focusableElement?.focus();
52590
52651
  }
52591
52652
  }, () => [this.sidePanel.isOpen]);
52653
+ useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
52654
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
52655
+ return scrollY > 0;
52656
+ });
52592
52657
  }
52593
52658
  onCellHovered({ col, row }) {
52594
52659
  this.hoveredCell.hover({ col, row });
@@ -53311,6 +53376,15 @@ class BordersPlugin extends CorePlugin {
53311
53376
  case "SET_BORDER":
53312
53377
  this.setBorder(cmd.sheetId, cmd.col, cmd.row, cmd.border);
53313
53378
  break;
53379
+ case "SET_BORDERS_ON_TARGET":
53380
+ for (const zone of cmd.target) {
53381
+ for (let row = zone.top; row <= zone.bottom; row++) {
53382
+ for (let col = zone.left; col <= zone.right; col++) {
53383
+ this.setBorder(cmd.sheetId, col, row, cmd.border);
53384
+ }
53385
+ }
53386
+ }
53387
+ break;
53314
53388
  case "SET_ZONE_BORDERS":
53315
53389
  if (cmd.border) {
53316
53390
  const target = cmd.target.map((zone) => this.getters.expandZone(cmd.sheetId, zone));
@@ -63073,25 +63147,6 @@ class AutofillPlugin extends UIPlugin {
63073
63147
  case "AUTOFILL_AUTO":
63074
63148
  this.autofillAuto();
63075
63149
  break;
63076
- case "AUTOFILL_CELL":
63077
- this.autoFillMerge(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
63078
- const sheetId = this.getters.getActiveSheetId();
63079
- this.dispatch("UPDATE_CELL", {
63080
- sheetId,
63081
- col: cmd.col,
63082
- row: cmd.row,
63083
- style: cmd.style || null,
63084
- content: cmd.content || "",
63085
- format: cmd.format || "",
63086
- });
63087
- this.dispatch("SET_BORDER", {
63088
- sheetId,
63089
- col: cmd.col,
63090
- row: cmd.row,
63091
- border: cmd.border,
63092
- });
63093
- this.autofillCF(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
63094
- this.autofillDV(cmd.originCol, cmd.originRow, cmd.col, cmd.row);
63095
63150
  }
63096
63151
  }
63097
63152
  // ---------------------------------------------------------------------------
@@ -63115,6 +63170,7 @@ class AutofillPlugin extends UIPlugin {
63115
63170
  }
63116
63171
  const source = this.getters.getSelectedZone();
63117
63172
  const target = this.autofillZone;
63173
+ const autofillCellsData = [];
63118
63174
  switch (this.direction) {
63119
63175
  case "down" /* DIRECTION.DOWN */:
63120
63176
  for (let col = source.left; col <= source.right; col++) {
@@ -63124,7 +63180,7 @@ class AutofillPlugin extends UIPlugin {
63124
63180
  }
63125
63181
  const generator = this.createGenerator(xcs);
63126
63182
  for (let row = target.top; row <= target.bottom; row++) {
63127
- this.computeNewCell(generator, col, row, apply);
63183
+ autofillCellsData.push(this.computeNewCell(generator, col, row));
63128
63184
  }
63129
63185
  }
63130
63186
  break;
@@ -63136,7 +63192,7 @@ class AutofillPlugin extends UIPlugin {
63136
63192
  }
63137
63193
  const generator = this.createGenerator(xcs);
63138
63194
  for (let row = target.bottom; row >= target.top; row--) {
63139
- this.computeNewCell(generator, col, row, apply);
63195
+ autofillCellsData.push(this.computeNewCell(generator, col, row));
63140
63196
  }
63141
63197
  }
63142
63198
  break;
@@ -63148,7 +63204,7 @@ class AutofillPlugin extends UIPlugin {
63148
63204
  }
63149
63205
  const generator = this.createGenerator(xcs);
63150
63206
  for (let col = target.right; col >= target.left; col--) {
63151
- this.computeNewCell(generator, col, row, apply);
63207
+ autofillCellsData.push(this.computeNewCell(generator, col, row));
63152
63208
  }
63153
63209
  }
63154
63210
  break;
@@ -63160,12 +63216,26 @@ class AutofillPlugin extends UIPlugin {
63160
63216
  }
63161
63217
  const generator = this.createGenerator(xcs);
63162
63218
  for (let col = target.left; col <= target.right; col++) {
63163
- this.computeNewCell(generator, col, row, apply);
63219
+ autofillCellsData.push(this.computeNewCell(generator, col, row));
63164
63220
  }
63165
63221
  }
63166
63222
  break;
63167
63223
  }
63168
63224
  if (apply) {
63225
+ const bordersZones = {};
63226
+ const cfNewRanges = {};
63227
+ const dvNewZones = {};
63228
+ const sheetId = this.getters.getActiveSheetId();
63229
+ for (const data of autofillCellsData) {
63230
+ this.collectBordersData(data, bordersZones);
63231
+ this.autofillMerge(sheetId, data);
63232
+ this.autofillCell(sheetId, data);
63233
+ this.collectConditionalFormatsData(sheetId, data, cfNewRanges);
63234
+ this.collectDataValidationsData(sheetId, data, dvNewZones);
63235
+ }
63236
+ this.autofillBorders(sheetId, bordersZones);
63237
+ this.autofillConditionalFormats(sheetId, cfNewRanges);
63238
+ this.autofillDataValidations(sheetId, dvNewZones);
63169
63239
  this.autofillZone = undefined;
63170
63240
  this.selection.resizeAnchorZone(this.direction, this.steps);
63171
63241
  this.lastCellSelected = {};
@@ -63174,6 +63244,95 @@ class AutofillPlugin extends UIPlugin {
63174
63244
  this.tooltip = undefined;
63175
63245
  }
63176
63246
  }
63247
+ collectBordersData(data, bordersPositions) {
63248
+ const key = JSON.stringify(data.border);
63249
+ if (!(key in bordersPositions)) {
63250
+ bordersPositions[key] = [];
63251
+ }
63252
+ bordersPositions[key].push(positionToZone({ col: data.col, row: data.row }));
63253
+ }
63254
+ collectConditionalFormatsData(sheetId, data, cfNewRanges) {
63255
+ const { originCol, originRow, col, row } = data;
63256
+ const cfsAtOrigin = this.getters.getRulesByCell(sheetId, originCol, originRow);
63257
+ const xc = toXC(col, row);
63258
+ for (const cf of cfsAtOrigin) {
63259
+ if (!(cf.id in cfNewRanges)) {
63260
+ cfNewRanges[cf.id] = [];
63261
+ }
63262
+ cfNewRanges[cf.id].push(xc);
63263
+ }
63264
+ }
63265
+ collectDataValidationsData(sheetId, data, dvNewZones) {
63266
+ const { originCol, originRow, col, row } = data;
63267
+ const cellPosition = { sheetId, col: originCol, row: originRow };
63268
+ const dvsAtOrigin = this.getters.getValidationRuleForCell(cellPosition);
63269
+ if (!dvsAtOrigin) {
63270
+ return;
63271
+ }
63272
+ if (!(dvsAtOrigin.id in dvNewZones)) {
63273
+ dvNewZones[dvsAtOrigin.id] = [];
63274
+ }
63275
+ dvNewZones[dvsAtOrigin.id].push(positionToZone({ col, row }));
63276
+ }
63277
+ autofillCell(sheetId, data) {
63278
+ this.dispatch("UPDATE_CELL", {
63279
+ sheetId,
63280
+ col: data.col,
63281
+ row: data.row,
63282
+ content: data.content || "",
63283
+ style: data.style || null,
63284
+ format: data.format || "",
63285
+ });
63286
+ // Still usefull in odoo ATM to autofill field sync
63287
+ this.dispatch("AUTOFILL_CELL", data);
63288
+ }
63289
+ autofillBorders(sheetId, bordersPositions) {
63290
+ for (const stringifiedBorder in bordersPositions) {
63291
+ const border = stringifiedBorder === "undefined" ? undefined : JSON.parse(stringifiedBorder);
63292
+ this.dispatch("SET_BORDERS_ON_TARGET", {
63293
+ sheetId,
63294
+ border,
63295
+ target: recomputeZones(bordersPositions[stringifiedBorder]),
63296
+ });
63297
+ }
63298
+ }
63299
+ autofillConditionalFormats(sheetId, cfNewRanges) {
63300
+ for (const cfId in cfNewRanges) {
63301
+ const changes = cfNewRanges[cfId];
63302
+ const cf = this.getters.getConditionalFormats(sheetId).find((cf) => cf.id === cfId);
63303
+ if (!cf) {
63304
+ continue;
63305
+ }
63306
+ const newCfRanges = this.getters.getAdaptedCfRanges(sheetId, cf, changes.map(toZone), []);
63307
+ if (newCfRanges) {
63308
+ this.dispatch("ADD_CONDITIONAL_FORMAT", {
63309
+ cf: {
63310
+ id: cf.id,
63311
+ rule: cf.rule,
63312
+ stopIfTrue: cf.stopIfTrue,
63313
+ },
63314
+ ranges: newCfRanges,
63315
+ sheetId,
63316
+ });
63317
+ }
63318
+ }
63319
+ }
63320
+ autofillDataValidations(sheetId, dvNewZones) {
63321
+ for (const dvId in dvNewZones) {
63322
+ const changes = dvNewZones[dvId];
63323
+ const dvOrigin = this.getters.getDataValidationRule(sheetId, dvId);
63324
+ if (!dvOrigin) {
63325
+ continue;
63326
+ }
63327
+ const dvRangesXcs = dvOrigin.ranges.map((range) => range.zone);
63328
+ const newDvRanges = recomputeZones(dvRangesXcs.concat(changes), []);
63329
+ this.dispatch("ADD_DATA_VALIDATION_RULE", {
63330
+ rule: dvOrigin,
63331
+ ranges: newDvRanges.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
63332
+ sheetId,
63333
+ });
63334
+ }
63335
+ }
63177
63336
  /**
63178
63337
  * Select a cell which becomes the last cell of the autofillZone
63179
63338
  */
@@ -63252,22 +63411,20 @@ class AutofillPlugin extends UIPlugin {
63252
63411
  /**
63253
63412
  * Generate the next cell
63254
63413
  */
63255
- computeNewCell(generator, col, row, apply) {
63414
+ computeNewCell(generator, col, row) {
63256
63415
  const { cellData, tooltip, origin } = generator.next();
63257
63416
  const { content, style, border, format } = cellData;
63258
63417
  this.tooltip = tooltip;
63259
- if (apply) {
63260
- this.dispatch("AUTOFILL_CELL", {
63261
- originCol: origin.col,
63262
- originRow: origin.row,
63263
- col,
63264
- row,
63265
- content,
63266
- style,
63267
- border,
63268
- format,
63269
- });
63270
- }
63418
+ return {
63419
+ originCol: origin.col,
63420
+ originRow: origin.row,
63421
+ col,
63422
+ row,
63423
+ content,
63424
+ style,
63425
+ border,
63426
+ format,
63427
+ };
63271
63428
  }
63272
63429
  /**
63273
63430
  * Get the rule associated to the current cell
@@ -63335,8 +63492,8 @@ class AutofillPlugin extends UIPlugin {
63335
63492
  ? position[first].value
63336
63493
  : position[second].value;
63337
63494
  }
63338
- autoFillMerge(originCol, originRow, col, row) {
63339
- const sheetId = this.getters.getActiveSheetId();
63495
+ autofillMerge(sheetId, data) {
63496
+ const { originCol, originRow, col, row } = data;
63340
63497
  const position = { sheetId, col, row };
63341
63498
  const originPosition = { sheetId, col: originCol, row: originRow };
63342
63499
  if (this.getters.isInMerge(position) && !this.getters.isInMerge(originPosition)) {
@@ -63363,35 +63520,6 @@ class AutofillPlugin extends UIPlugin {
63363
63520
  });
63364
63521
  }
63365
63522
  }
63366
- autofillCF(originCol, originRow, col, row) {
63367
- const sheetId = this.getters.getActiveSheetId();
63368
- const cfOrigin = this.getters.getRulesByCell(sheetId, originCol, originRow);
63369
- for (const cf of cfOrigin) {
63370
- const newCfRanges = this.getters.getAdaptedCfRanges(sheetId, cf, [positionToZone({ col, row })], []);
63371
- if (newCfRanges) {
63372
- this.dispatch("ADD_CONDITIONAL_FORMAT", {
63373
- cf: deepCopy(cf),
63374
- ranges: newCfRanges,
63375
- sheetId,
63376
- });
63377
- }
63378
- }
63379
- }
63380
- autofillDV(originCol, originRow, col, row) {
63381
- const sheetId = this.getters.getActiveSheetId();
63382
- const cellPosition = { sheetId, col: originCol, row: originRow };
63383
- const dvOrigin = this.getters.getValidationRuleForCell(cellPosition);
63384
- if (!dvOrigin) {
63385
- return;
63386
- }
63387
- const dvRangesZones = dvOrigin.ranges.map((range) => range.zone);
63388
- const newDvRanges = recomputeZones(dvRangesZones.concat(positionToZone({ col, row })), []);
63389
- this.dispatch("ADD_DATA_VALIDATION_RULE", {
63390
- rule: dvOrigin,
63391
- ranges: newDvRanges.map((zone) => this.getters.getRangeDataFromZone(sheetId, zone)),
63392
- sheetId,
63393
- });
63394
- }
63395
63523
  // ---------------------------------------------------------------------------
63396
63524
  // Grid rendering
63397
63525
  // ---------------------------------------------------------------------------
@@ -63771,10 +63899,8 @@ function mergeTransformation(toTransform, executed) {
63771
63899
  }
63772
63900
  const target = [];
63773
63901
  for (const zone1 of toTransform.target) {
63774
- for (const zone2 of executed.target) {
63775
- if (!overlap(zone1, zone2)) {
63776
- target.push({ ...zone1 });
63777
- }
63902
+ if (executed.target.every((zone2) => !overlap(zone1, zone2))) {
63903
+ target.push(zone1);
63778
63904
  }
63779
63905
  }
63780
63906
  if (target.length) {
@@ -67906,24 +68032,14 @@ class InternalViewport {
67906
68032
  first: this.boundaries.top,
67907
68033
  last: this.boundaries.bottom,
67908
68034
  });
67909
- const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
67910
- const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
67911
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
67912
- const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
67913
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
67914
- const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
68035
+ const { end: lastColEnd } = this.getters.getColDimensions(this.sheetId, lastCol);
68036
+ const { end: lastRowEnd } = this.getters.getRowDimensions(this.sheetId, lastRow);
67915
68037
  let width = lastColEnd - this.offsetCorrectionX;
67916
68038
  if (this.canScrollHorizontally) {
67917
- width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
67918
- Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
67919
- );
67920
68039
  width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
67921
68040
  }
67922
68041
  let height = lastRowEnd - this.offsetCorrectionY;
67923
68042
  if (this.canScrollVertically) {
67924
- height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
67925
- Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
67926
- );
67927
68043
  height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
67928
68044
  if (lastRowEnd + FOOTER_HEIGHT > height && !this.getters.isReadonly()) {
67929
68045
  height += FOOTER_HEIGHT;
@@ -68488,8 +68604,8 @@ class SheetViewPlugin extends UIPlugin {
68488
68604
  const { width, height } = this.getMainViewportRect();
68489
68605
  const viewport = this.getMainInternalViewport(sheetId);
68490
68606
  return {
68491
- maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
68492
- maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
68607
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth),
68608
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight),
68493
68609
  };
68494
68610
  }
68495
68611
  getColRowOffsetInViewport(dimension, referenceHeaderIndex, targetHeaderIndex) {
@@ -70011,6 +70127,10 @@ class SpreadsheetDashboard extends Component {
70011
70127
  this.hoveredCell.clear();
70012
70128
  });
70013
70129
  this.cellPopovers = useStore(CellPopoverStore);
70130
+ useTouchScroll(gridRef, this.moveCanvas.bind(this), () => {
70131
+ const { scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
70132
+ return scrollY > 0;
70133
+ });
70014
70134
  }
70015
70135
  onCellHovered({ col, row }) {
70016
70136
  this.hoveredCell.hover({ col, row });
@@ -71401,6 +71521,7 @@ css /* scss */ `
71401
71521
  > canvas {
71402
71522
  box-sizing: content-box;
71403
71523
  border-bottom: 1px solid #e2e3e3;
71524
+ border-right: 1px solid #e2e3e3;
71404
71525
  }
71405
71526
 
71406
71527
  .o-grid-overlay {
@@ -76062,6 +76183,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
76062
76183
  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, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
76063
76184
 
76064
76185
 
76065
- __info__.version = "18.2.6";
76066
- __info__.date = "2025-04-04T08:41:26.115Z";
76067
- __info__.hash = "faa00e2";
76186
+ __info__.version = "18.2.8";
76187
+ __info__.date = "2025-04-18T16:26:20.673Z";
76188
+ __info__.hash = "5da9ddc";