@odoo/o-spreadsheet 17.2.6 → 17.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.
@@ -3,12 +3,12 @@
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.6
7
- * @date 2024-05-07T10:41:20.332Z
8
- * @hash a4f800c
6
+ * @version 17.2.8
7
+ * @date 2024-05-24T11:29:49.320Z
8
+ * @hash bfbcaa0
9
9
  */
10
10
 
11
- import { reactive, useEnv, useSubEnv, useState, onWillUnmount, markRaw, toRaw, Component, useRef, onMounted, useEffect, onPatched, useComponent, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv } from '@odoo/owl';
11
+ import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw } from '@odoo/owl';
12
12
 
13
13
  const CANVAS_SHIFT = 0.5;
14
14
  // Colors
@@ -502,6 +502,26 @@ function debounce(func, wait, immediate) {
502
502
  };
503
503
  return debounced;
504
504
  }
505
+ /**
506
+ * Creates a batched version of a callback so that all calls to it in the same
507
+ * microtick will only call the original callback once.
508
+ *
509
+ * @param callback the callback to batch
510
+ * @returns a batched version of the original callback
511
+ *
512
+ * Copied from odoo/owl repo.
513
+ */
514
+ function batched(callback) {
515
+ let scheduled = false;
516
+ return async (...args) => {
517
+ if (!scheduled) {
518
+ scheduled = true;
519
+ await Promise.resolve();
520
+ scheduled = false;
521
+ callback(...args);
522
+ }
523
+ };
524
+ }
505
525
  /*
506
526
  * Concatenate an array of strings.
507
527
  */
@@ -576,8 +596,9 @@ function deepEquals(o1, o2, ignoreFunctions) {
576
596
  return false;
577
597
  }
578
598
  else {
579
- if (ignoreFunctions && typeOfO1Key === "function")
580
- return true;
599
+ if (ignoreFunctions && typeOfO1Key === "function") {
600
+ continue;
601
+ }
581
602
  if (o1[key] !== o2[key])
582
603
  return false;
583
604
  }
@@ -1828,7 +1849,7 @@ class LazyTranslatedString extends String {
1828
1849
  }
1829
1850
  valueOf() {
1830
1851
  const str = super.valueOf();
1831
- return _loaded() ? sprintf(_translate(str), ...this.values) : str;
1852
+ return _loaded() ? sprintf(_translate(str), ...this.values) : sprintf(str, ...this.values);
1832
1853
  }
1833
1854
  toString() {
1834
1855
  return this.valueOf();
@@ -5201,7 +5222,7 @@ function tokenizeString(chars) {
5201
5222
  }
5202
5223
  return null;
5203
5224
  }
5204
- const separatorRegexp = /^[\w\.!\$]+/;
5225
+ const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
5205
5226
  /**
5206
5227
  * A "Symbol" is just basically any word-like element that can appear in a
5207
5228
  * formula, which is not a string. So:
@@ -5241,11 +5262,8 @@ function tokenizeSymbol(chars) {
5241
5262
  };
5242
5263
  }
5243
5264
  }
5244
- const match = chars.remaining().match(separatorRegexp);
5245
- if (match) {
5246
- const value = match[0];
5247
- result += value;
5248
- chars.advanceBy(value.length);
5265
+ while (chars.current && SYMBOL_CHARS.has(chars.current)) {
5266
+ result += chars.shift();
5249
5267
  }
5250
5268
  if (result.length) {
5251
5269
  const value = result;
@@ -6797,7 +6815,7 @@ const machine = {
6797
6815
  function matchReference(tokens) {
6798
6816
  let head = 0;
6799
6817
  let transitions = machine[State.LeftRef];
6800
- const matchedTokens = [];
6818
+ let matchedTokens = "";
6801
6819
  while (transitions !== undefined) {
6802
6820
  const token = tokens[head++];
6803
6821
  if (!token) {
@@ -6809,15 +6827,15 @@ function matchReference(tokens) {
6809
6827
  case undefined:
6810
6828
  return null;
6811
6829
  case State.Found:
6812
- matchedTokens.push(token);
6830
+ matchedTokens += token.value;
6813
6831
  tokens.splice(0, head);
6814
6832
  return {
6815
6833
  type: "REFERENCE",
6816
- value: concat(matchedTokens.map((token) => token.value)),
6834
+ value: matchedTokens,
6817
6835
  };
6818
6836
  default:
6819
6837
  transitions = machine[nextState];
6820
- matchedTokens.push(token);
6838
+ matchedTokens += token.value;
6821
6839
  break;
6822
6840
  }
6823
6841
  }
@@ -8015,10 +8033,66 @@ function getDateCriterionFormattedValues(criterion, getters) {
8015
8033
  });
8016
8034
  }
8017
8035
 
8036
+ /**
8037
+ * This is a generic event bus based on the Owl event bus.
8038
+ * This bus however ensures type safety across events and subscription callbacks.
8039
+ */
8040
+ class EventBus {
8041
+ subscriptions = {};
8042
+ /**
8043
+ * Add a listener for the 'eventType' events.
8044
+ *
8045
+ * Note that the 'owner' of this event can be anything, but will more likely
8046
+ * be a component or a class. The idea is that the callback will be called with
8047
+ * the proper owner bound.
8048
+ *
8049
+ * Also, the owner should be kind of unique. This will be used to remove the
8050
+ * listener.
8051
+ */
8052
+ on(type, owner, callback) {
8053
+ if (!callback) {
8054
+ throw new Error("Missing callback");
8055
+ }
8056
+ if (!this.subscriptions[type]) {
8057
+ this.subscriptions[type] = [];
8058
+ }
8059
+ this.subscriptions[type].push({
8060
+ owner,
8061
+ callback,
8062
+ });
8063
+ }
8064
+ /**
8065
+ * Emit an event of type 'eventType'. Any extra arguments will be passed to
8066
+ * the listeners callback.
8067
+ */
8068
+ trigger(type, payload) {
8069
+ const subs = this.subscriptions[type] || [];
8070
+ for (let i = 0, iLen = subs.length; i < iLen; i++) {
8071
+ const sub = subs[i];
8072
+ sub.callback.call(sub.owner, payload);
8073
+ }
8074
+ }
8075
+ /**
8076
+ * Remove a listener
8077
+ */
8078
+ off(eventType, owner) {
8079
+ const subs = this.subscriptions[eventType];
8080
+ if (subs) {
8081
+ this.subscriptions[eventType] = subs.filter((s) => s.owner !== owner);
8082
+ }
8083
+ }
8084
+ /**
8085
+ * Remove all subscriptions.
8086
+ */
8087
+ clear() {
8088
+ this.subscriptions = {};
8089
+ }
8090
+ }
8091
+
8018
8092
  /**
8019
8093
  * A type-safe dependency container
8020
8094
  */
8021
- class DependencyContainer {
8095
+ class DependencyContainer extends EventBus {
8022
8096
  dependencies = new Map();
8023
8097
  factory = new StoreFactory(this.get.bind(this));
8024
8098
  /**
@@ -8095,15 +8169,12 @@ stores.inject(MyMetaStore, storeInstance);
8095
8169
  }
8096
8170
  return MetaStore;
8097
8171
  }
8098
- class ReactiveStore {
8172
+ class DisposableStore {
8099
8173
  get;
8174
+ disposeCallbacks = [];
8100
8175
  constructor(get) {
8101
8176
  this.get = get;
8102
- return reactive(this);
8103
8177
  }
8104
- }
8105
- class DisposableStore extends ReactiveStore {
8106
- disposeCallbacks = [];
8107
8178
  onDispose(callback) {
8108
8179
  this.disposeCallbacks.push(callback);
8109
8180
  }
@@ -8123,7 +8194,10 @@ function useStoreProvider() {
8123
8194
  const container = new DependencyContainer();
8124
8195
  useSubEnv({
8125
8196
  __spreadsheet_stores__: container,
8126
- getStore: container.get.bind(container),
8197
+ getStore: (Store) => {
8198
+ const store = container.get(Store);
8199
+ return proxifyStoreMutation(store, () => container.trigger("store-updated"));
8200
+ },
8127
8201
  });
8128
8202
  return container;
8129
8203
  }
@@ -8133,14 +8207,57 @@ function useStoreProvider() {
8133
8207
  function useStore(Store) {
8134
8208
  const env = useEnv();
8135
8209
  const container = getDependencyContainer(env);
8136
- return useState(container.get(Store));
8210
+ const store = container.get(Store);
8211
+ return useStoreRenderProxy(container, store);
8137
8212
  }
8138
8213
  function useLocalStore(Store, ...args) {
8139
8214
  const env = useEnv();
8140
8215
  const container = getDependencyContainer(env);
8141
- const store = useState(container.instantiate(Store, ...args));
8216
+ const store = container.instantiate(Store, ...args);
8142
8217
  onWillUnmount(() => store.dispose());
8143
- return store;
8218
+ return useStoreRenderProxy(container, store);
8219
+ }
8220
+ /**
8221
+ * Trigger an event to re-render the app (deep render) when
8222
+ * a store is mutated by invoking one of its mutator methods.
8223
+ */
8224
+ function useStoreRenderProxy(container, store) {
8225
+ const component = useComponent();
8226
+ const proxy = proxifyStoreMutation(store, () => {
8227
+ if (status(component) === "mounted") {
8228
+ container.trigger("store-updated");
8229
+ }
8230
+ });
8231
+ return proxy;
8232
+ }
8233
+ /**
8234
+ * Creates a proxied version of a store object with mutation tracking.
8235
+ * Whenever a mutator method of the store is called, the provided callback function is invoked.
8236
+ */
8237
+ function proxifyStoreMutation(store, callback) {
8238
+ const proxy = new Proxy(store, {
8239
+ get(target, property, receiver) {
8240
+ const thisStore = target;
8241
+ // The third argument is `thisStore` (target) instead of `receiver`.
8242
+ // The goal is to always have the same `this` value in getter functions
8243
+ // (when `target[property]` is an accessor property).
8244
+ // `thisStore` is always the same object reference. `receiver` however is the
8245
+ // object on which the property is called, which is the Proxy object which is different for each component.
8246
+ const value = Reflect.get(target, property, thisStore);
8247
+ if (store.mutators.includes(property)) {
8248
+ const functionProxy = new Proxy(value, {
8249
+ // trap the function call
8250
+ apply(target, thisArg, argArray) {
8251
+ Reflect.apply(target, thisStore, argArray);
8252
+ callback();
8253
+ },
8254
+ });
8255
+ return functionProxy;
8256
+ }
8257
+ return value;
8258
+ },
8259
+ });
8260
+ return proxy;
8144
8261
  }
8145
8262
  function getDependencyContainer(env) {
8146
8263
  const container = env.__spreadsheet_stores__;
@@ -8152,7 +8269,8 @@ function getDependencyContainer(env) {
8152
8269
 
8153
8270
  const ModelStore = createAbstractStore("Model");
8154
8271
 
8155
- class RendererStore extends ReactiveStore {
8272
+ class RendererStore {
8273
+ mutators = ["register", "unRegister"];
8156
8274
  renderers = {};
8157
8275
  register(renderer) {
8158
8276
  if (!renderer.renderingLayers.length) {
@@ -8186,7 +8304,7 @@ class RendererStore extends ReactiveStore {
8186
8304
  class SpreadsheetStore extends DisposableStore {
8187
8305
  // cast the model store as Model to allow model.dispatch to return the DispatchResult
8188
8306
  model = this.get(ModelStore);
8189
- getters = markRaw(this.model.getters);
8307
+ getters = this.model.getters;
8190
8308
  renderer = this.get(RendererStore);
8191
8309
  constructor(get) {
8192
8310
  super(get);
@@ -8233,6 +8351,7 @@ function drawHighlight(renderingContext, highlight, rect) {
8233
8351
  }
8234
8352
 
8235
8353
  class HighlightStore extends SpreadsheetStore {
8354
+ mutators = ["register", "unRegister"];
8236
8355
  providers = [];
8237
8356
  constructor(get) {
8238
8357
  super(get);
@@ -8263,7 +8382,7 @@ class HighlightStore extends SpreadsheetStore {
8263
8382
  this.providers.push(highlightProvider);
8264
8383
  }
8265
8384
  unRegister(highlightProvider) {
8266
- this.providers = this.providers.filter((h) => toRaw(h) !== toRaw(highlightProvider));
8385
+ this.providers = this.providers.filter((h) => h !== highlightProvider);
8267
8386
  }
8268
8387
  drawLayer(ctx, layer) {
8269
8388
  if (layer === "Highlights") {
@@ -8279,6 +8398,16 @@ const NotificationStore = createAbstractStore("Notifications");
8279
8398
 
8280
8399
  const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
8281
8400
  class ComposerStore extends SpreadsheetStore {
8401
+ mutators = [
8402
+ "startEdition",
8403
+ "setCurrentContent",
8404
+ "stopEdition",
8405
+ "stopComposerRangeSelection",
8406
+ "cancelEdition",
8407
+ "cycleReferences",
8408
+ "changeComposerCursorSelection",
8409
+ "replaceComposerCursorSelection",
8410
+ ];
8282
8411
  col = 0;
8283
8412
  row = 0;
8284
8413
  editionMode = "inactive";
@@ -8293,9 +8422,9 @@ class ComposerStore extends SpreadsheetStore {
8293
8422
  highlightStore = this.get(HighlightStore);
8294
8423
  constructor(get) {
8295
8424
  super(get);
8296
- this.highlightStore.register(toRaw(this));
8425
+ this.highlightStore.register(this);
8297
8426
  this.onDispose(() => {
8298
- this.highlightStore.unRegister(toRaw(this));
8427
+ this.highlightStore.unRegister(this);
8299
8428
  });
8300
8429
  }
8301
8430
  canStopEdition() {
@@ -8422,7 +8551,7 @@ class ComposerStore extends SpreadsheetStore {
8422
8551
  if (this.isSelectingRange) {
8423
8552
  this.editionMode = "editing";
8424
8553
  }
8425
- this.model.selection.resetAnchor(toRaw(this), {
8554
+ this.model.selection.resetAnchor(this, {
8426
8555
  cell: { col: left, row: top },
8427
8556
  zone: cmd.zone,
8428
8557
  });
@@ -8440,7 +8569,7 @@ class ComposerStore extends SpreadsheetStore {
8440
8569
  row: activePosition.row,
8441
8570
  });
8442
8571
  const zone = this.getters.expandZone(cmd.sheetIdTo, positionToZone({ col, row }));
8443
- this.model.selection.resetAnchor(toRaw(this), { cell: { col, row }, zone });
8572
+ this.model.selection.resetAnchor(this, { cell: { col, row }, zone });
8444
8573
  }
8445
8574
  break;
8446
8575
  case "DELETE_SHEET":
@@ -8539,7 +8668,7 @@ class ComposerStore extends SpreadsheetStore {
8539
8668
  startComposerRangeSelection() {
8540
8669
  if (this.sheetId === this.getters.getActiveSheetId()) {
8541
8670
  const zone = positionToZone({ col: this.col, row: this.row });
8542
- this.model.selection.resetAnchor(toRaw(this), {
8671
+ this.model.selection.resetAnchor(this, {
8543
8672
  cell: { col: this.col, row: this.row },
8544
8673
  zone,
8545
8674
  });
@@ -8568,7 +8697,7 @@ class ComposerStore extends SpreadsheetStore {
8568
8697
  this.setContent(str || this.initialContent, selection);
8569
8698
  this.colorIndexByRange = {};
8570
8699
  const zone = positionToZone({ col: this.col, row: this.row });
8571
- this.model.selection.capture(toRaw(this), { cell: { col: this.col, row: this.row }, zone }, {
8700
+ this.model.selection.capture(this, { cell: { col: this.col, row: this.row }, zone }, {
8572
8701
  handleEvent: this.handleEvent.bind(this),
8573
8702
  release: () => {
8574
8703
  this._stopEdition();
@@ -8676,7 +8805,7 @@ class ComposerStore extends SpreadsheetStore {
8676
8805
  return;
8677
8806
  }
8678
8807
  this.editionMode = "inactive";
8679
- this.model.selection.release(toRaw(this));
8808
+ this.model.selection.release(this);
8680
8809
  }
8681
8810
  /**
8682
8811
  * Reset the current content to the active cell content
@@ -8998,6 +9127,7 @@ class ComposerStore extends SpreadsheetStore {
8998
9127
  }
8999
9128
 
9000
9129
  class ComposerFocusStore extends SpreadsheetStore {
9130
+ mutators = ["focusTopBarComposer", "focusGridComposerContent", "focusGridComposerCell"];
9001
9131
  composerStore = this.get(ComposerStore);
9002
9132
  topBarFocus = "inactive";
9003
9133
  gridFocusMode = "inactive";
@@ -21454,6 +21584,7 @@ function interactiveAddMerge(env, sheetId, target) {
21454
21584
  }
21455
21585
 
21456
21586
  class HoveredCellStore extends SpreadsheetStore {
21587
+ mutators = ["clear", "hover"];
21457
21588
  col;
21458
21589
  row;
21459
21590
  handle(cmd) {
@@ -21473,6 +21604,7 @@ class HoveredCellStore extends SpreadsheetStore {
21473
21604
  }
21474
21605
 
21475
21606
  class CellPopoverStore extends SpreadsheetStore {
21607
+ mutators = ["open", "close"];
21476
21608
  persistentPopover;
21477
21609
  hoveredCell = this.get(HoveredCellStore);
21478
21610
  handle(cmd) {
@@ -25964,12 +26096,13 @@ function updateSelectionWithArrowKeys(ev, selection) {
25964
26096
 
25965
26097
  // The name is misleading and can be confused with the DOM focus.
25966
26098
  class FocusStore {
26099
+ mutators = ["focus", "unfocus"];
25967
26100
  focusedElement = null;
25968
26101
  focus(element) {
25969
26102
  this.focusedElement = element;
25970
26103
  }
25971
26104
  unfocus(element) {
25972
- if (this.focusedElement && toRaw(this.focusedElement) === toRaw(element)) {
26105
+ if (this.focusedElement && this.focusedElement === element) {
25973
26106
  this.focusedElement = null;
25974
26107
  }
25975
26108
  }
@@ -25985,6 +26118,16 @@ class FocusStore {
25985
26118
  class SelectionInputStore extends SpreadsheetStore {
25986
26119
  initialRanges;
25987
26120
  inputHasSingleRange;
26121
+ mutators = [
26122
+ "resetWithRanges",
26123
+ "focusById",
26124
+ "unfocus",
26125
+ "addEmptyRange",
26126
+ "removeRange",
26127
+ "changeRange",
26128
+ "reset",
26129
+ "confirm",
26130
+ ];
25988
26131
  ranges = [];
25989
26132
  focusedRangeIndex = null;
25990
26133
  inputSheetId;
@@ -26044,7 +26187,7 @@ class SelectionInputStore extends SpreadsheetStore {
26044
26187
  row: 0,
26045
26188
  });
26046
26189
  const zone = this.getters.expandZone(cmd.sheetIdTo, positionToZone({ col, row }));
26047
- this.model.selection.resetAnchor(toRaw(this), { cell: { col, row }, zone });
26190
+ this.model.selection.resetAnchor(this, { cell: { col, row }, zone });
26048
26191
  }
26049
26192
  break;
26050
26193
  }
@@ -26063,7 +26206,7 @@ class SelectionInputStore extends SpreadsheetStore {
26063
26206
  if (focusIndex !== -1) {
26064
26207
  this.focus(focusIndex);
26065
26208
  const { left, top } = newZone;
26066
- this.model.selection.resetAnchor(toRaw(this), {
26209
+ this.model.selection.resetAnchor(this, {
26067
26210
  cell: { col: left, row: top },
26068
26211
  zone: newZone,
26069
26212
  });
@@ -26154,7 +26297,7 @@ class SelectionInputStore extends SpreadsheetStore {
26154
26297
  }
26155
26298
  get hasMainFocus() {
26156
26299
  const focusedElement = this.focusStore.focusedElement;
26157
- return !!focusedElement && toRaw(focusedElement) === toRaw(this);
26300
+ return !!focusedElement && focusedElement === this;
26158
26301
  }
26159
26302
  get highlights() {
26160
26303
  if (!this.hasMainFocus) {
@@ -26183,7 +26326,7 @@ class SelectionInputStore extends SpreadsheetStore {
26183
26326
  unfocus() {
26184
26327
  this.focusedRangeIndex = null;
26185
26328
  this.focusStore.unfocus(this);
26186
- this.model.selection.release(toRaw(this));
26329
+ this.model.selection.release(this);
26187
26330
  }
26188
26331
  captureSelection() {
26189
26332
  if (this.focusedRangeIndex === null) {
@@ -26192,7 +26335,7 @@ class SelectionInputStore extends SpreadsheetStore {
26192
26335
  const range = this.ranges[this.focusedRangeIndex];
26193
26336
  const sheetId = this.getters.getActiveSheetId();
26194
26337
  const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
26195
- this.model.selection.capture(toRaw(this), { cell: { col: zone.left, row: zone.top }, zone }, {
26338
+ this.model.selection.capture(this, { cell: { col: zone.left, row: zone.top }, zone }, {
26196
26339
  handleEvent: this.handleEvent.bind(this),
26197
26340
  release: this.unfocus.bind(this),
26198
26341
  });
@@ -27660,6 +27803,7 @@ chartSidePanelComponentRegistry
27660
27803
  });
27661
27804
 
27662
27805
  class MainChartPanelStore extends SpreadsheetStore {
27806
+ mutators = ["activatePanel"];
27663
27807
  panel = "configuration";
27664
27808
  activatePanel(panel) {
27665
27809
  this.panel = panel;
@@ -28198,14 +28342,14 @@ function useHoveredElement(ref) {
28198
28342
 
28199
28343
  function useHighlightsOnHover(ref, highlightProvider) {
28200
28344
  const hoverState = useHoveredElement(ref);
28201
- const env = useEnv();
28345
+ const stores = useStoreProvider();
28202
28346
  useHighlights({
28203
28347
  get highlights() {
28204
28348
  return hoverState.hovered ? highlightProvider.highlights : [];
28205
28349
  },
28206
28350
  });
28207
28351
  useEffect(() => {
28208
- env.model.dispatch("RENDER_CANVAS");
28352
+ stores.trigger("store-updated");
28209
28353
  }, () => [hoverState.hovered]);
28210
28354
  }
28211
28355
  function useHighlights(highlightProvider) {
@@ -29661,6 +29805,14 @@ var Direction;
29661
29805
  Direction[Direction["next"] = 1] = "next";
29662
29806
  })(Direction || (Direction = {}));
29663
29807
  class FindAndReplaceStore extends SpreadsheetStore {
29808
+ mutators = [
29809
+ "updateSearchOptions",
29810
+ "updateSearchContent",
29811
+ "searchFormulas",
29812
+ "selectPreviousMatch",
29813
+ "selectNextMatch",
29814
+ "replace",
29815
+ ];
29664
29816
  allSheetsMatches = [];
29665
29817
  activeSheetMatches = [];
29666
29818
  specificRangeMatches = [];
@@ -29685,11 +29837,11 @@ class FindAndReplaceStore extends SpreadsheetStore {
29685
29837
  this.initialShowFormulaState = this.model.getters.shouldShowFormulas();
29686
29838
  this.searchOptions.searchFormulas = this.initialShowFormulaState;
29687
29839
  const highlightStore = get(HighlightStore);
29688
- highlightStore.register(toRaw(this));
29840
+ highlightStore.register(this);
29689
29841
  this.onDispose(() => {
29690
29842
  this.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.initialShowFormulaState });
29691
29843
  this.updateSearchContent.stopDebounce();
29692
- highlightStore.unRegister(toRaw(this));
29844
+ highlightStore.unRegister(this);
29693
29845
  });
29694
29846
  }
29695
29847
  get searchMatches() {
@@ -31332,6 +31484,7 @@ unGroupHeadersMenuRegistry
31332
31484
  });
31333
31485
 
31334
31486
  class DOMFocusableElementStore {
31487
+ mutators = ["setFocusableElement", "focus"];
31335
31488
  focusableElement = undefined;
31336
31489
  setFocusableElement(element) {
31337
31490
  this.focusableElement = element;
@@ -32068,7 +32221,7 @@ class Composer extends Component {
32068
32221
  "Ctrl+Enter": this.processNewLineEvent,
32069
32222
  Escape: this.processEscapeKey,
32070
32223
  F2: () => console.warn("Not implemented"),
32071
- F4: this.processF4Key,
32224
+ F4: (ev) => this.processF4Key(ev),
32072
32225
  Tab: (ev) => this.processTabKey(ev, "right"),
32073
32226
  "Shift+Tab": (ev) => this.processTabKey(ev, "left"),
32074
32227
  };
@@ -32190,7 +32343,8 @@ class Composer extends Component {
32190
32343
  processEscapeKey() {
32191
32344
  this.composerStore.cancelEdition();
32192
32345
  }
32193
- processF4Key() {
32346
+ processF4Key(ev) {
32347
+ ev.stopPropagation();
32194
32348
  this.composerStore.cycleReferences();
32195
32349
  this.processContent();
32196
32350
  }
@@ -34393,13 +34547,6 @@ class GridRenderer {
34393
34547
  this.getters = get(ModelStore).getters;
34394
34548
  this.renderer = get(RendererStore);
34395
34549
  this.renderer.register(this);
34396
- /**
34397
- * Mark the instance as raw to avoid reactivity as this class is instanciated
34398
- * as a Store by `useGridDrawing` (which casts it as reactive).
34399
- *
34400
- * Calling `this.` on a reactive instance is significantly slower than on a raw object.
34401
- */
34402
- markRaw(this);
34403
34550
  }
34404
34551
  get renderingLayers() {
34405
34552
  return ["Background", "Headers"];
@@ -35029,7 +35176,7 @@ class GridRenderer {
35029
35176
  function useGridDrawing(refName, model, canvasSize) {
35030
35177
  const canvasRef = useRef(refName);
35031
35178
  useEffect(drawGrid);
35032
- const rendererManager = useStore(RendererStore);
35179
+ const rendererStore = useStore(RendererStore);
35033
35180
  useStore(GridRenderer);
35034
35181
  function drawGrid() {
35035
35182
  const canvas = canvasRef.el;
@@ -35057,7 +35204,11 @@ function useGridDrawing(refName, model, canvasSize) {
35057
35204
  ctx.scale(dpr, dpr);
35058
35205
  for (const layer of OrderedLayers()) {
35059
35206
  model.drawLayer(renderingContext, layer);
35060
- rendererManager.drawLayer(renderingContext, layer);
35207
+ // @ts-ignore 'drawLayer' is not declated as a mutator because:
35208
+ // it does not mutate anything. Most importantly it's used
35209
+ // during rendering. Invoking a mutator during rendering would
35210
+ // trigger another rendering, ultimately resulting in an infinite loop.
35211
+ rendererStore.drawLayer(renderingContext, layer);
35061
35212
  }
35062
35213
  }
35063
35214
  }
@@ -35459,6 +35610,7 @@ class VerticalScrollBar extends Component {
35459
35610
  }
35460
35611
 
35461
35612
  class SidePanelStore extends SpreadsheetStore {
35613
+ mutators = ["open", "toggle", "close"];
35462
35614
  initialPanelProps = {};
35463
35615
  componentTag = "";
35464
35616
  get isOpen() {
@@ -43287,7 +43439,12 @@ class MergePlugin extends CorePlugin {
43287
43439
  * if they have at least a common cell
43288
43440
  */
43289
43441
  doesIntersectMerge(sheetId, zone) {
43290
- return positions(zone).some(({ col, row }) => this.getMerge({ sheetId, col, row }) !== undefined);
43442
+ for (const merge of this.getMerges(sheetId)) {
43443
+ if (overlap(zone, merge)) {
43444
+ return true;
43445
+ }
43446
+ }
43447
+ return false;
43291
43448
  }
43292
43449
  /**
43293
43450
  * Returns true if two columns have at least one merge in common
@@ -47435,9 +47592,10 @@ class Evaluator {
47435
47592
  }
47436
47593
  if (!content) {
47437
47594
  // The previous content could have blocked some array formulas
47438
- impactedPositions.addMany(this.getArrayFormulasBlockedBy(position));
47595
+ impactedPositions.add(position);
47439
47596
  }
47440
47597
  }
47598
+ impactedPositions.addMany(this.getArrayFormulasBlockedBy(impactedPositions));
47441
47599
  return impactedPositions;
47442
47600
  }
47443
47601
  buildDependencyGraph() {
@@ -47479,23 +47637,25 @@ class Evaluator {
47479
47637
  return positions;
47480
47638
  }
47481
47639
  /**
47482
- * Return the position of formulas blocked by the given position
47640
+ * Return the position of formulas blocked by the given positions
47483
47641
  * as well as all their dependencies.
47484
47642
  */
47485
- getArrayFormulasBlockedBy(position) {
47486
- if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
47487
- return [];
47488
- }
47489
- const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
47490
- const positions = this.createEmptyPositionSet();
47491
- positions.addMany(arrayFormulas);
47492
- const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
47493
- if (arrayFormulaPosition) {
47494
- // ignore the formula spreading on the position. Keep only the blocked ones
47495
- positions.delete(arrayFormulaPosition);
47643
+ getArrayFormulasBlockedBy(positions) {
47644
+ const arrayFormulaPositions = this.createEmptyPositionSet();
47645
+ for (const position of positions) {
47646
+ if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
47647
+ continue;
47648
+ }
47649
+ const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
47650
+ arrayFormulaPositions.addMany(arrayFormulas);
47651
+ const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
47652
+ if (arrayFormulaPosition) {
47653
+ // ignore the formula spreading on the position. Keep only the blocked ones
47654
+ arrayFormulaPositions.delete(arrayFormulaPosition);
47655
+ }
47496
47656
  }
47497
- positions.addMany(this.getCellsDependingOn(positions));
47498
- return positions;
47657
+ arrayFormulaPositions.addMany(this.getCellsDependingOn(arrayFormulaPositions));
47658
+ return arrayFormulaPositions;
47499
47659
  }
47500
47660
  nextPositionsToUpdate = new PositionSet({});
47501
47661
  cellsBeingComputed = new Set();
@@ -47625,6 +47785,7 @@ class Evaluator {
47625
47785
  if (!this.spreadingRelations.isArrayFormula(position)) {
47626
47786
  return;
47627
47787
  }
47788
+ const invalidated = this.createEmptyPositionSet();
47628
47789
  for (const child of this.spreadingRelations.getArrayResultPositions(position)) {
47629
47790
  const content = this.getters.getCell(child)?.content;
47630
47791
  if (content) {
@@ -47632,10 +47793,11 @@ class Evaluator {
47632
47793
  // there's still a collision
47633
47794
  continue;
47634
47795
  }
47796
+ invalidated.add(child);
47635
47797
  this.evaluatedCells.delete(child);
47636
- this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
47637
- this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedBy(child));
47638
47798
  }
47799
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn(invalidated));
47800
+ this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedBy(invalidated));
47639
47801
  this.spreadingRelations.removeNode(position);
47640
47802
  }
47641
47803
  // ----------------------------------------------------------
@@ -49602,62 +49764,6 @@ class AutomaticSumPlugin extends UIPlugin {
49602
49764
  }
49603
49765
  }
49604
49766
 
49605
- /**
49606
- * This is a generic event bus based on the Owl event bus.
49607
- * This bus however ensures type safety across events and subscription callbacks.
49608
- */
49609
- class EventBus {
49610
- subscriptions = {};
49611
- /**
49612
- * Add a listener for the 'eventType' events.
49613
- *
49614
- * Note that the 'owner' of this event can be anything, but will more likely
49615
- * be a component or a class. The idea is that the callback will be called with
49616
- * the proper owner bound.
49617
- *
49618
- * Also, the owner should be kind of unique. This will be used to remove the
49619
- * listener.
49620
- */
49621
- on(type, owner, callback) {
49622
- if (!callback) {
49623
- throw new Error("Missing callback");
49624
- }
49625
- if (!this.subscriptions[type]) {
49626
- this.subscriptions[type] = [];
49627
- }
49628
- this.subscriptions[type].push({
49629
- owner,
49630
- callback,
49631
- });
49632
- }
49633
- /**
49634
- * Emit an event of type 'eventType'. Any extra arguments will be passed to
49635
- * the listeners callback.
49636
- */
49637
- trigger(type, payload) {
49638
- const subs = this.subscriptions[type] || [];
49639
- for (let i = 0, iLen = subs.length; i < iLen; i++) {
49640
- const sub = subs[i];
49641
- sub.callback.call(sub.owner, payload);
49642
- }
49643
- }
49644
- /**
49645
- * Remove a listener
49646
- */
49647
- off(eventType, owner) {
49648
- const subs = this.subscriptions[eventType];
49649
- if (subs) {
49650
- this.subscriptions[eventType] = subs.filter((s) => s.owner !== owner);
49651
- }
49652
- }
49653
- /**
49654
- * Remove all subscriptions.
49655
- */
49656
- clear() {
49657
- this.subscriptions = {};
49658
- }
49659
- }
49660
-
49661
49767
  /*
49662
49768
  * This file contains the specifics transformations
49663
49769
  */
@@ -52128,7 +52234,7 @@ class ClipboardPlugin extends UIPlugin {
52128
52234
  case "ADD_COLUMNS_ROWS": {
52129
52235
  this.status = "invisible";
52130
52236
  // If we add a col/row inside or before the cut area, we invalidate the clipboard
52131
- if (this._isCutOperation !== true) {
52237
+ if (this._isCutOperation !== true || cmd.sheetId !== this.copiedData?.sheetId) {
52132
52238
  return;
52133
52239
  }
52134
52240
  const isClipboardDirty = this.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
@@ -52140,7 +52246,7 @@ class ClipboardPlugin extends UIPlugin {
52140
52246
  case "REMOVE_COLUMNS_ROWS": {
52141
52247
  this.status = "invisible";
52142
52248
  // If we remove a col/row inside or before the cut area, we invalidate the clipboard
52143
- if (this._isCutOperation !== true) {
52249
+ if (this._isCutOperation !== true || cmd.sheetId !== this.copiedData?.sheetId) {
52144
52250
  return;
52145
52251
  }
52146
52252
  for (let el of cmd.elements) {
@@ -56775,16 +56881,25 @@ class Spreadsheet extends Component {
56775
56881
  }
56776
56882
  }, () => [this.env.model.getters.getActiveSheetId()]);
56777
56883
  useExternalListener(window, "resize", () => this.render(true));
56884
+ // For some reason, the wheel event is not properly registered inside templates
56885
+ // in Chromium-based browsers based on chromium 125
56886
+ // This hack ensures the event declared in the template is properly registered/working
56887
+ useExternalListener(document.body, "wheel", () => { });
56778
56888
  this.bindModelEvents();
56779
56889
  onWillUpdateProps((nextProps) => {
56780
56890
  if (nextProps.model !== this.props.model) {
56781
56891
  throw new Error("Changing the props model is not supported at the moment.");
56782
56892
  }
56783
56893
  });
56894
+ const render = batched(this.render.bind(this, true));
56784
56895
  onMounted(() => {
56785
56896
  this.checkViewportSize();
56897
+ stores.on("store-updated", this, render);
56898
+ });
56899
+ onWillUnmount(() => {
56900
+ this.unbindModelEvents();
56901
+ stores.off("store-updated", this);
56786
56902
  });
56787
- onWillUnmount(() => this.unbindModelEvents());
56788
56903
  onPatched(() => {
56789
56904
  this.checkViewportSize();
56790
56905
  });
@@ -60572,6 +60687,6 @@ const constants = {
60572
60687
  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 };
60573
60688
 
60574
60689
 
60575
- __info__.version = "17.2.6";
60576
- __info__.date = "2024-05-07T10:41:20.332Z";
60577
- __info__.hash = "a4f800c";
60690
+ __info__.version = "17.2.8";
60691
+ __info__.date = "2024-05-24T11:29:49.320Z";
60692
+ __info__.hash = "bfbcaa0";