@odoo/o-spreadsheet 18.2.0-alpha.2 → 18.2.0-alpha.3

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.0-alpha.2
6
- * @date 2025-01-15T08:06:32.137Z
7
- * @hash 4f96c47
5
+ * @version 18.2.0-alpha.3
6
+ * @date 2025-01-27T10:07:28.716Z
7
+ * @hash 63a13e5
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -4390,15 +4390,18 @@
4390
4390
  let currentIndex;
4391
4391
  let currentVal;
4392
4392
  let currentType;
4393
+ const getValue = sortOrder === "desc"
4394
+ ? (i) => normalizeValue(getValueInData(data, rangeLength - i - 1))
4395
+ : (i) => normalizeValue(getValueInData(data, i));
4393
4396
  while (indexRight - indexLeft >= 0) {
4394
4397
  indexMedian = Math.floor((indexLeft + indexRight) / 2);
4395
4398
  currentIndex = indexMedian;
4396
- currentVal = normalizeValue(getValueInData(data, currentIndex));
4399
+ currentVal = getValue(currentIndex);
4397
4400
  currentType = typeof currentVal;
4398
4401
  // 1 - linear search to find value with the same type
4399
4402
  while (indexLeft < currentIndex && targetType !== currentType) {
4400
4403
  currentIndex--;
4401
- currentVal = normalizeValue(getValueInData(data, currentIndex));
4404
+ currentVal = getValue(currentIndex);
4402
4405
  currentType = typeof currentVal;
4403
4406
  }
4404
4407
  if (currentType !== targetType || currentVal === undefined || currentVal === null) {
@@ -4414,8 +4417,7 @@
4414
4417
  if (matchVal === undefined ||
4415
4418
  matchVal === null ||
4416
4419
  matchVal < currentVal ||
4417
- (matchVal === currentVal && sortOrder === "asc" && matchValIndex < currentIndex) ||
4418
- (matchVal === currentVal && sortOrder === "desc" && matchValIndex > currentIndex)) {
4420
+ (matchVal === currentVal && matchValIndex < currentIndex)) {
4419
4421
  matchVal = currentVal;
4420
4422
  matchValIndex = currentIndex;
4421
4423
  }
@@ -4423,15 +4425,13 @@
4423
4425
  else if (mode === "nextGreater" && currentVal >= _target) {
4424
4426
  if (matchVal === undefined ||
4425
4427
  matchVal > currentVal ||
4426
- (matchVal === currentVal && sortOrder === "asc" && matchValIndex < currentIndex) ||
4427
- (matchVal === currentVal && sortOrder === "desc" && matchValIndex > currentIndex)) {
4428
+ (matchVal === currentVal && matchValIndex < currentIndex)) {
4428
4429
  matchVal = currentVal;
4429
4430
  matchValIndex = currentIndex;
4430
4431
  }
4431
4432
  }
4432
4433
  // 3 - give new indexes for the Binary search
4433
- if ((sortOrder === "asc" && currentVal > _target) ||
4434
- (sortOrder === "desc" && currentVal <= _target)) {
4434
+ if (currentVal > _target || (mode === "strict" && currentVal === _target)) {
4435
4435
  indexRight = currentIndex - 1;
4436
4436
  }
4437
4437
  else {
@@ -4439,7 +4439,10 @@
4439
4439
  }
4440
4440
  }
4441
4441
  // note that valMinIndex could be 0
4442
- return matchValIndex !== undefined ? matchValIndex : -1;
4442
+ if (matchValIndex === undefined) {
4443
+ return -1;
4444
+ }
4445
+ return sortOrder === "desc" ? rangeLength - matchValIndex - 1 : matchValIndex;
4443
4446
  }
4444
4447
  /**
4445
4448
  * Perform a linear search and return the index of the match.
@@ -8004,6 +8007,7 @@
8004
8007
  integer: NUMBER_CHAR_AGGREGATORS,
8005
8008
  char: NUMBER_CHAR_AGGREGATORS,
8006
8009
  boolean: ["count_distinct", "count", "bool_and", "bool_or"],
8010
+ datetime: ["max", "min", "count_distinct", "count"],
8007
8011
  };
8008
8012
  const AGGREGATORS = {};
8009
8013
  for (const type in AGGREGATORS_BY_FIELD_TYPE) {
@@ -9809,13 +9813,13 @@ stores.inject(MyMetaStore, storeInstance);
9809
9813
  else if (ds.labelCell) {
9810
9814
  label = {
9811
9815
  reference: getters.getRangeString(ds.labelCell, "forceSheetReference", {
9812
- useFixedReference: true,
9816
+ useBoundedReference: true,
9813
9817
  }),
9814
9818
  };
9815
9819
  }
9816
9820
  return {
9817
9821
  label,
9818
- range: getters.getRangeString(dataRange, "forceSheetReference", { useFixedReference: true }),
9822
+ range: getters.getRangeString(dataRange, "forceSheetReference", { useBoundedReference: true }),
9819
9823
  backgroundColor: ds.backgroundColor,
9820
9824
  rightYAxis: ds.rightYAxis,
9821
9825
  };
@@ -9830,7 +9834,7 @@ stores.inject(MyMetaStore, storeInstance);
9830
9834
  zone.top = zone.top + 1;
9831
9835
  }
9832
9836
  const range = labelRange.clone({ zone });
9833
- return getters.getRangeString(range, "forceSheetReference", { useFixedReference: true });
9837
+ return getters.getRangeString(range, "forceSheetReference", { useBoundedReference: true });
9834
9838
  }
9835
9839
  /**
9836
9840
  * Transform a chart definition which supports dataSets (dataSets and LabelRange)
@@ -29580,11 +29584,14 @@ stores.inject(MyMetaStore, storeInstance);
29580
29584
  </t>
29581
29585
  </templates>
29582
29586
  `;
29583
- const app = new owl.App(owl.Component, { templates, translateFn: _t });
29587
+ let app;
29584
29588
  function renderToString(templateName, context = {}) {
29585
29589
  return render(templateName, context).innerHTML;
29586
29590
  }
29587
29591
  function render(templateName, context = {}) {
29592
+ if (!app) {
29593
+ app = new owl.App(owl.Component, { templates, translateFn: _t });
29594
+ }
29588
29595
  const templateFn = app.getTemplate(templateName);
29589
29596
  const bdom = templateFn(context, {});
29590
29597
  const div = document.createElement("div");
@@ -29813,6 +29820,7 @@ stores.inject(MyMetaStore, storeInstance);
29813
29820
  getBarChartLegend: getBarChartLegend,
29814
29821
  getBarChartScales: getBarChartScales,
29815
29822
  getBarChartTooltip: getBarChartTooltip,
29823
+ getChartColorsGenerator: getChartColorsGenerator,
29816
29824
  getChartLabelFormat: getChartLabelFormat,
29817
29825
  getChartLayout: getChartLayout,
29818
29826
  getChartShowValues: getChartShowValues,
@@ -32345,6 +32353,10 @@ stores.inject(MyMetaStore, storeInstance);
32345
32353
  this.currentDisplayValue = newDisplay;
32346
32354
  if (!anchor)
32347
32355
  return;
32356
+ el.style.top = "";
32357
+ el.style.left = "";
32358
+ el.style["max-height"] = "";
32359
+ el.style["max-width"] = "";
32348
32360
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
32349
32361
  let elDims = {
32350
32362
  width: el.getBoundingClientRect().width,
@@ -36981,6 +36993,440 @@ stores.inject(MyMetaStore, storeInstance);
36981
36993
  };
36982
36994
  }
36983
36995
 
36996
+ /**
36997
+ * Start listening to pointer events and apply the given callbacks.
36998
+ *
36999
+ * @returns A function to remove the listeners.
37000
+ */
37001
+ function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
37002
+ const removeListeners = () => {
37003
+ window.removeEventListener("pointerdown", onMouseDown);
37004
+ window.removeEventListener("pointerup", _onMouseUp);
37005
+ window.removeEventListener("dragstart", _onDragStart);
37006
+ window.removeEventListener("pointermove", onMouseMove);
37007
+ window.removeEventListener("wheel", onMouseMove);
37008
+ };
37009
+ const _onMouseUp = (ev) => {
37010
+ onMouseUp(ev);
37011
+ removeListeners();
37012
+ };
37013
+ function _onDragStart(ev) {
37014
+ ev.preventDefault();
37015
+ }
37016
+ window.addEventListener("pointerdown", onMouseDown);
37017
+ window.addEventListener("pointerup", _onMouseUp);
37018
+ window.addEventListener("dragstart", _onDragStart);
37019
+ window.addEventListener("pointermove", onMouseMove);
37020
+ // mouse wheel on window is by default a passive event.
37021
+ // preventDefault() is not allowed in passive event handler.
37022
+ // https://chromestatus.com/feature/6662647093133312
37023
+ window.addEventListener("wheel", onMouseMove, { passive: false });
37024
+ return removeListeners;
37025
+ }
37026
+ /**
37027
+ * Function to be used during a pointerdown event, this function allows to
37028
+ * perform actions related to the pointermove and pointerup events and adjusts the viewport
37029
+ * when the new position related to the pointermove event is outside of it.
37030
+ * Among inputs are two callback functions. First intended for actions performed during
37031
+ * the pointermove event, it receives as parameters the current position of the pointermove
37032
+ * (occurrence of the current column and the current row). Second intended for actions
37033
+ * performed during the pointerup event.
37034
+ */
37035
+ function dragAndDropBeyondTheViewport(env, cbMouseMove, cbMouseUp, only = false) {
37036
+ let timeOutId = null;
37037
+ let currentEv;
37038
+ let previousEv;
37039
+ let startingEv;
37040
+ let startingX;
37041
+ let startingY;
37042
+ const getters = env.model.getters;
37043
+ const sheetId = getters.getActiveSheetId();
37044
+ const position = gridOverlayPosition();
37045
+ let colIndex;
37046
+ let rowIndex;
37047
+ const onMouseDown = (ev) => {
37048
+ previousEv = ev;
37049
+ startingEv = ev;
37050
+ startingX = startingEv.clientX - position.left;
37051
+ startingY = startingEv.clientY - position.top;
37052
+ };
37053
+ const onMouseMove = (ev) => {
37054
+ currentEv = ev;
37055
+ if (timeOutId) {
37056
+ return;
37057
+ }
37058
+ const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
37059
+ let { top, left, bottom, right } = getters.getActiveMainViewport();
37060
+ let { scrollX, scrollY } = getters.getActiveSheetDOMScrollInfo();
37061
+ const { xSplit, ySplit } = getters.getPaneDivisions(sheetId);
37062
+ let canEdgeScroll = false;
37063
+ let timeoutDelay = MAX_DELAY;
37064
+ const x = currentEv.clientX - position.left;
37065
+ colIndex = getters.getColIndex(x);
37066
+ if (only !== "vertical") {
37067
+ const previousX = previousEv.clientX - position.left;
37068
+ const edgeScrollInfoX = getters.getEdgeScrollCol(x, previousX, startingX);
37069
+ if (edgeScrollInfoX.canEdgeScroll) {
37070
+ canEdgeScroll = true;
37071
+ timeoutDelay = Math.min(timeoutDelay, edgeScrollInfoX.delay);
37072
+ let newTarget;
37073
+ switch (edgeScrollInfoX.direction) {
37074
+ case "reset":
37075
+ colIndex = xSplit;
37076
+ newTarget = xSplit;
37077
+ break;
37078
+ case 1:
37079
+ colIndex = right;
37080
+ newTarget = left + 1;
37081
+ break;
37082
+ case -1:
37083
+ colIndex = left - 1;
37084
+ while (env.model.getters.isColHidden(sheetId, colIndex)) {
37085
+ colIndex--;
37086
+ }
37087
+ newTarget = colIndex;
37088
+ break;
37089
+ }
37090
+ scrollX = getters.getColDimensions(sheetId, newTarget).start - offsetCorrectionX;
37091
+ }
37092
+ }
37093
+ const y = currentEv.clientY - position.top;
37094
+ rowIndex = getters.getRowIndex(y);
37095
+ if (only !== "horizontal") {
37096
+ const previousY = previousEv.clientY - position.top;
37097
+ const edgeScrollInfoY = getters.getEdgeScrollRow(y, previousY, startingY);
37098
+ if (edgeScrollInfoY.canEdgeScroll) {
37099
+ canEdgeScroll = true;
37100
+ timeoutDelay = Math.min(timeoutDelay, edgeScrollInfoY.delay);
37101
+ let newTarget;
37102
+ switch (edgeScrollInfoY.direction) {
37103
+ case "reset":
37104
+ rowIndex = ySplit;
37105
+ newTarget = ySplit;
37106
+ break;
37107
+ case 1:
37108
+ rowIndex = bottom;
37109
+ newTarget = top + edgeScrollInfoY.direction;
37110
+ break;
37111
+ case -1:
37112
+ rowIndex = top - 1;
37113
+ while (env.model.getters.isRowHidden(sheetId, rowIndex)) {
37114
+ rowIndex--;
37115
+ }
37116
+ newTarget = rowIndex;
37117
+ break;
37118
+ }
37119
+ scrollY = env.model.getters.getRowDimensions(sheetId, newTarget).start - offsetCorrectionY;
37120
+ }
37121
+ }
37122
+ if (!canEdgeScroll) {
37123
+ if (rowIndex === -1) {
37124
+ rowIndex = y < 0 ? 0 : getters.getNumberRows(sheetId) - 1;
37125
+ }
37126
+ if (colIndex === -1 && x < 0) {
37127
+ colIndex = x < 0 ? 0 : getters.getNumberCols(sheetId) - 1;
37128
+ }
37129
+ }
37130
+ cbMouseMove(colIndex, rowIndex, currentEv);
37131
+ if (canEdgeScroll) {
37132
+ env.model.dispatch("SET_VIEWPORT_OFFSET", { offsetX: scrollX, offsetY: scrollY });
37133
+ timeOutId = setTimeout(() => {
37134
+ timeOutId = null;
37135
+ onMouseMove(currentEv);
37136
+ }, Math.round(timeoutDelay));
37137
+ }
37138
+ previousEv = currentEv;
37139
+ };
37140
+ const onMouseUp = () => {
37141
+ clearTimeout(timeOutId);
37142
+ cbMouseUp();
37143
+ };
37144
+ startDnd(onMouseMove, onMouseUp, onMouseDown);
37145
+ }
37146
+
37147
+ function useDragAndDropListItems() {
37148
+ let dndHelper;
37149
+ const previousCursor = document.body.style.cursor;
37150
+ let cleanupFns = [];
37151
+ const cleanUp = () => {
37152
+ dndHelper = undefined;
37153
+ document.body.style.cursor = previousCursor;
37154
+ cleanupFns.forEach((fn) => fn());
37155
+ cleanupFns = [];
37156
+ };
37157
+ const start = (direction, args) => {
37158
+ const onChange = () => {
37159
+ document.body.style.cursor = "move";
37160
+ if (!dndHelper)
37161
+ return;
37162
+ Object.assign(state.itemsStyle, dndHelper.getItemStyles());
37163
+ args.onChange?.();
37164
+ };
37165
+ state.cancel = () => {
37166
+ state.draggedItemId = undefined;
37167
+ state.itemsStyle = {};
37168
+ document.body.style.cursor = previousCursor;
37169
+ args.onCancel?.();
37170
+ cleanUp();
37171
+ };
37172
+ const onDragEnd = (itemId, indexAtEnd) => {
37173
+ state.draggedItemId = undefined;
37174
+ state.itemsStyle = {};
37175
+ document.body.style.cursor = previousCursor;
37176
+ args.onDragEnd?.(itemId, indexAtEnd);
37177
+ cleanUp();
37178
+ };
37179
+ document.body.style.cursor = "move";
37180
+ state.draggedItemId = args.draggedItemId;
37181
+ const container = direction === "horizontal"
37182
+ ? new HorizontalContainer(args.containerEl)
37183
+ : new VerticalContainer(args.containerEl);
37184
+ dndHelper = new DOMDndHelper({
37185
+ ...args,
37186
+ container,
37187
+ onChange,
37188
+ onDragEnd,
37189
+ onCancel: state.cancel,
37190
+ });
37191
+ const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
37192
+ cleanupFns.push(stopListening);
37193
+ const onScroll = dndHelper.onScroll.bind(dndHelper);
37194
+ args.containerEl.addEventListener("scroll", onScroll);
37195
+ cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
37196
+ cleanupFns.push(dndHelper.destroy.bind(dndHelper));
37197
+ };
37198
+ owl.onWillUnmount(() => {
37199
+ cleanUp();
37200
+ });
37201
+ const state = owl.useState({
37202
+ itemsStyle: {},
37203
+ draggedItemId: undefined,
37204
+ start,
37205
+ cancel: () => { },
37206
+ });
37207
+ return state;
37208
+ }
37209
+ class DOMDndHelper {
37210
+ draggedItemId;
37211
+ items;
37212
+ container;
37213
+ initialMousePosition;
37214
+ currentMousePosition;
37215
+ initialScroll;
37216
+ minPosition;
37217
+ maxPosition;
37218
+ edgeScrollIntervalId;
37219
+ onChange;
37220
+ onCancel;
37221
+ onDragEnd;
37222
+ /**
37223
+ * The dead zone is an area in which the pointermove events are ignored.
37224
+ *
37225
+ * This is useful when swapping the dragged item with a larger item. After the swap,
37226
+ * the mouse is still hovering on the item we just swapped with. In this case, we don't want
37227
+ * a mouse move to trigger another swap the other way around, so we create a dead zone. We will clear
37228
+ * the dead zone when the mouse leaves the swapped item.
37229
+ */
37230
+ deadZone;
37231
+ constructor(args) {
37232
+ this.items = args.items.map((item) => ({ ...item, positionAtStart: item.position }));
37233
+ this.draggedItemId = args.draggedItemId;
37234
+ this.container = args.container;
37235
+ this.onChange = args.onChange;
37236
+ this.onCancel = args.onCancel;
37237
+ this.onDragEnd = args.onDragEnd;
37238
+ this.initialMousePosition = args.initialMousePosition;
37239
+ this.currentMousePosition = args.initialMousePosition;
37240
+ this.initialScroll = this.container.scroll;
37241
+ this.minPosition = this.items[0].position;
37242
+ this.maxPosition =
37243
+ this.items[this.items.length - 1].position + this.items[this.items.length - 1].size;
37244
+ }
37245
+ getItemStyles() {
37246
+ const styles = {};
37247
+ for (let item of this.items) {
37248
+ styles[item.id] = this.getItemStyle(item.id);
37249
+ }
37250
+ return styles;
37251
+ }
37252
+ getItemStyle(itemId) {
37253
+ const position = this.container.cssPositionProperty;
37254
+ const style = {};
37255
+ style.position = "relative";
37256
+ style[position] = (this.getItemsPositions()[itemId] || 0) + "px";
37257
+ style.transition = `${position} 0.5s`;
37258
+ style["pointer-events"] = "none";
37259
+ if (this.draggedItemId === itemId) {
37260
+ style.transition = `${position} 0s`;
37261
+ style["z-index"] = "1000";
37262
+ }
37263
+ return cssPropertiesToCss(style);
37264
+ }
37265
+ onScroll() {
37266
+ this.moveDraggedItemToPosition(this.currentMousePosition + this.scrollOffset);
37267
+ }
37268
+ onMouseMove(ev) {
37269
+ if (ev.button > 1) {
37270
+ this.onCancel();
37271
+ return;
37272
+ }
37273
+ const mousePosition = this.container.getMousePosition(ev);
37274
+ this.currentMousePosition = mousePosition;
37275
+ if (mousePosition < this.container.start || mousePosition > this.container.end) {
37276
+ this.startEdgeScroll(mousePosition < this.container.start ? -1 : 1);
37277
+ return;
37278
+ }
37279
+ else {
37280
+ this.stopEdgeScroll();
37281
+ }
37282
+ this.moveDraggedItemToPosition(mousePosition + this.scrollOffset);
37283
+ }
37284
+ moveDraggedItemToPosition(position) {
37285
+ const hoveredItemIndex = this.getHoveredItemIndex(position, this.items);
37286
+ const draggedItemIndex = this.items.findIndex((item) => item.id === this.draggedItemId);
37287
+ const draggedItem = this.items[draggedItemIndex];
37288
+ if (this.deadZone && this.isInZone(position, this.deadZone)) {
37289
+ this.onChange(this.getItemsPositions());
37290
+ return;
37291
+ }
37292
+ else if (this.isInZone(position, {
37293
+ start: draggedItem.position,
37294
+ end: draggedItem.position + draggedItem.size,
37295
+ })) {
37296
+ this.deadZone = undefined;
37297
+ }
37298
+ if (draggedItemIndex === hoveredItemIndex) {
37299
+ this.onChange(this.getItemsPositions());
37300
+ return;
37301
+ }
37302
+ const startIndex = Math.min(draggedItemIndex, hoveredItemIndex);
37303
+ const endIndex = Math.max(draggedItemIndex, hoveredItemIndex);
37304
+ const direction = Math.sign(hoveredItemIndex - draggedItemIndex);
37305
+ let draggedItemMoveSize = 0;
37306
+ for (let i = startIndex; i <= endIndex; i++) {
37307
+ if (i === draggedItemIndex) {
37308
+ continue;
37309
+ }
37310
+ this.items[i].position -= direction * draggedItem.size;
37311
+ draggedItemMoveSize += this.items[i].size;
37312
+ }
37313
+ draggedItem.position += direction * draggedItemMoveSize;
37314
+ this.items.sort((item1, item2) => item1.position - item2.position);
37315
+ this.deadZone =
37316
+ direction > 0
37317
+ ? { start: position, end: draggedItem.position }
37318
+ : { start: draggedItem.position + draggedItem.size, end: position };
37319
+ this.onChange(this.getItemsPositions());
37320
+ }
37321
+ onMouseUp(ev) {
37322
+ if (ev.button !== 0) {
37323
+ this.onCancel();
37324
+ }
37325
+ ev.stopPropagation();
37326
+ ev.preventDefault();
37327
+ const targetItemIndex = this.items.findIndex((item) => item.id === this.draggedItemId);
37328
+ this.onDragEnd(this.draggedItemId, targetItemIndex);
37329
+ this.stopEdgeScroll();
37330
+ return false;
37331
+ }
37332
+ startEdgeScroll(direction) {
37333
+ if (this.edgeScrollIntervalId)
37334
+ return;
37335
+ this.edgeScrollIntervalId = window.setInterval(() => {
37336
+ const offset = direction * 3;
37337
+ this.container.scroll += offset;
37338
+ }, 5);
37339
+ }
37340
+ stopEdgeScroll() {
37341
+ window.clearInterval(this.edgeScrollIntervalId);
37342
+ this.edgeScrollIntervalId = undefined;
37343
+ }
37344
+ /**
37345
+ * Get the index of the item the given mouse position is inside.
37346
+ * If the mouse is outside the container, return the first or last item index.
37347
+ */
37348
+ getHoveredItemIndex(mousePosition, items) {
37349
+ if (mousePosition <= this.minPosition)
37350
+ return 0;
37351
+ if (mousePosition >= this.maxPosition)
37352
+ return items.length - 1;
37353
+ return items.findIndex((item) => item.position + item.size >= mousePosition);
37354
+ }
37355
+ getItemsPositions() {
37356
+ const positions = {};
37357
+ for (let item of this.items) {
37358
+ if (item.id !== this.draggedItemId) {
37359
+ positions[item.id] = item.position - item.positionAtStart;
37360
+ continue;
37361
+ }
37362
+ const mouseOffset = this.currentMousePosition - this.initialMousePosition;
37363
+ let start = mouseOffset + this.scrollOffset;
37364
+ start = Math.max(this.minPosition - item.positionAtStart, start);
37365
+ start = Math.min(this.maxPosition - item.positionAtStart - item.size, start);
37366
+ positions[item.id] = start;
37367
+ }
37368
+ return positions;
37369
+ }
37370
+ isInZone(position, zone) {
37371
+ return position >= zone.start && position <= zone.end;
37372
+ }
37373
+ get scrollOffset() {
37374
+ return this.container.scroll - this.initialScroll;
37375
+ }
37376
+ destroy() {
37377
+ this.stopEdgeScroll();
37378
+ }
37379
+ }
37380
+ class ContainerWrapper {
37381
+ el;
37382
+ constructor(el) {
37383
+ this.el = el;
37384
+ }
37385
+ get containerRect() {
37386
+ return this.el.getBoundingClientRect();
37387
+ }
37388
+ }
37389
+ class VerticalContainer extends ContainerWrapper {
37390
+ get start() {
37391
+ return this.containerRect.top;
37392
+ }
37393
+ get end() {
37394
+ return this.containerRect.bottom;
37395
+ }
37396
+ get cssPositionProperty() {
37397
+ return "top";
37398
+ }
37399
+ get scroll() {
37400
+ return this.el.scrollTop;
37401
+ }
37402
+ set scroll(scroll) {
37403
+ this.el.scrollTop = scroll;
37404
+ }
37405
+ getMousePosition(ev) {
37406
+ return ev.clientY;
37407
+ }
37408
+ }
37409
+ class HorizontalContainer extends ContainerWrapper {
37410
+ get start() {
37411
+ return this.containerRect.left;
37412
+ }
37413
+ get end() {
37414
+ return this.containerRect.right;
37415
+ }
37416
+ get cssPositionProperty() {
37417
+ return "left";
37418
+ }
37419
+ get scroll() {
37420
+ return this.el.scrollLeft;
37421
+ }
37422
+ set scroll(scroll) {
37423
+ this.el.scrollLeft = scroll;
37424
+ }
37425
+ getMousePosition(ev) {
37426
+ return ev.clientX;
37427
+ }
37428
+ }
37429
+
36984
37430
  const arrowMap = {
36985
37431
  ArrowDown: "down",
36986
37432
  ArrowLeft: "left",
@@ -37031,6 +37477,7 @@ stores.inject(MyMetaStore, storeInstance);
37031
37477
  "changeRange",
37032
37478
  "reset",
37033
37479
  "confirm",
37480
+ "updateColors",
37034
37481
  ];
37035
37482
  ranges = [];
37036
37483
  focusedRangeIndex = null;
@@ -37150,6 +37597,9 @@ stores.inject(MyMetaStore, storeInstance);
37150
37597
  this.removeRangeByIndex(index);
37151
37598
  }
37152
37599
  }
37600
+ updateColors(colors) {
37601
+ this.colors = colors;
37602
+ }
37153
37603
  confirm() {
37154
37604
  for (const range of this.selectionInputs) {
37155
37605
  if (range.xc === "") {
@@ -37360,6 +37810,9 @@ stores.inject(MyMetaStore, storeInstance);
37360
37810
  right: 7px;
37361
37811
  top: 4px;
37362
37812
  }
37813
+ .o-drag-handle {
37814
+ cursor: move;
37815
+ }
37363
37816
  }
37364
37817
  .o-button {
37365
37818
  height: 28px;
@@ -37391,13 +37844,17 @@ stores.inject(MyMetaStore, storeInstance);
37391
37844
  class: { type: String, optional: true },
37392
37845
  onSelectionChanged: { type: Function, optional: true },
37393
37846
  onSelectionConfirmed: { type: Function, optional: true },
37847
+ onSelectionReordered: { type: Function, optional: true },
37848
+ onSelectionRemoved: { type: Function, optional: true },
37394
37849
  colors: { type: Array, optional: true, default: [] },
37395
37850
  };
37396
37851
  state = owl.useState({
37397
37852
  isMissing: false,
37398
37853
  mode: "select-range",
37399
37854
  });
37855
+ dragAndDrop = useDragAndDropListItems();
37400
37856
  focusedInput = owl.useRef("focusedInput");
37857
+ selectionRef = owl.useRef("o-selection");
37401
37858
  store;
37402
37859
  get ranges() {
37403
37860
  return this.store.selectionInputs;
@@ -37425,8 +37882,45 @@ stores.inject(MyMetaStore, storeInstance);
37425
37882
  nextProps.ranges.join() !== this.store.selectionInputValues.join()) {
37426
37883
  this.store.resetWithRanges(nextProps.ranges);
37427
37884
  }
37885
+ if (nextProps.colors?.join() !== this.props.colors?.join() &&
37886
+ nextProps.colors?.join() !== this.store.colors.join()) {
37887
+ this.store.updateColors(nextProps.colors || []);
37888
+ }
37889
+ });
37890
+ }
37891
+ startDragAndDrop(rangeId, event) {
37892
+ if (event.button !== 0 || event.target.tagName === "SELECT") {
37893
+ return;
37894
+ }
37895
+ const rects = this.getRangeElementsRects();
37896
+ const draggableIds = this.ranges.map((range) => range.id);
37897
+ const draggableItems = draggableIds.map((id, index) => ({
37898
+ id: id.toString(),
37899
+ size: rects[index].height,
37900
+ position: rects[index].y,
37901
+ }));
37902
+ this.dragAndDrop.start("vertical", {
37903
+ draggedItemId: rangeId.toString(),
37904
+ initialMousePosition: event.clientY,
37905
+ items: draggableItems,
37906
+ containerEl: this.selectionRef.el,
37907
+ onDragEnd: (dimensionName, finalIndex) => {
37908
+ const originalIndex = draggableIds.findIndex((id) => id === rangeId);
37909
+ if (originalIndex === finalIndex) {
37910
+ return;
37911
+ }
37912
+ const draggedItems = [...draggableIds];
37913
+ draggedItems.splice(originalIndex, 1);
37914
+ draggedItems.splice(finalIndex, 0, rangeId);
37915
+ this.props.onSelectionReordered?.(this.store.selectionInputs.map((range) => draggedItems.indexOf(range.id)));
37916
+ this.props.onSelectionConfirmed?.();
37917
+ this.store.confirm();
37918
+ },
37428
37919
  });
37429
37920
  }
37921
+ getRangeElementsRects() {
37922
+ return Array.from(this.selectionRef.el.children).map((el) => el.getBoundingClientRect());
37923
+ }
37430
37924
  getColor(range) {
37431
37925
  if (!range.color) {
37432
37926
  return "";
@@ -37468,8 +37962,8 @@ stores.inject(MyMetaStore, storeInstance);
37468
37962
  this.store.addEmptyRange();
37469
37963
  }
37470
37964
  removeInput(rangeId) {
37471
- this.store.removeRange(rangeId);
37472
- this.triggerChange();
37965
+ const index = this.store.selectionInputs.findIndex((range) => range.id === rangeId);
37966
+ this.props.onSelectionRemoved?.(index);
37473
37967
  this.props.onSelectionConfirmed?.();
37474
37968
  }
37475
37969
  onInputChanged(rangeId, ev) {
@@ -37500,6 +37994,8 @@ stores.inject(MyMetaStore, storeInstance);
37500
37994
  ranges: Array,
37501
37995
  hasSingleRange: { type: Boolean, optional: true },
37502
37996
  onSelectionChanged: Function,
37997
+ onSelectionReordered: { type: Function, optional: true },
37998
+ onSelectionRemoved: { type: Function, optional: true },
37503
37999
  onSelectionConfirmed: Function,
37504
38000
  };
37505
38001
  get ranges() {
@@ -37608,11 +38104,11 @@ stores.inject(MyMetaStore, storeInstance);
37608
38104
  datasetDispatchResult: undefined,
37609
38105
  labelsDispatchResult: undefined,
37610
38106
  });
37611
- dataSeriesRanges = [];
38107
+ dataSets = [];
37612
38108
  labelRange;
37613
38109
  chartTerms = ChartTerms;
37614
38110
  setup() {
37615
- this.dataSeriesRanges = this.props.definition.dataSets;
38111
+ this.dataSets = this.props.definition.dataSets;
37616
38112
  this.labelRange = this.props.definition.labelRange;
37617
38113
  }
37618
38114
  get errorMessages() {
@@ -37657,22 +38153,46 @@ stores.inject(MyMetaStore, storeInstance);
37657
38153
  * button "confirm" is clicked
37658
38154
  */
37659
38155
  onDataSeriesRangesChanged(ranges) {
37660
- this.dataSeriesRanges = ranges.map((dataRange, i) => ({
37661
- ...this.dataSeriesRanges?.[i],
38156
+ this.dataSets = ranges.map((dataRange, i) => ({
38157
+ ...this.dataSets?.[i],
37662
38158
  dataRange,
37663
38159
  }));
37664
38160
  this.state.datasetDispatchResult = this.props.canUpdateChart(this.props.figureId, {
37665
- dataSets: this.dataSeriesRanges,
38161
+ dataSets: this.dataSets,
38162
+ });
38163
+ }
38164
+ onDataSeriesReordered(indexes) {
38165
+ const colorGenerator = getChartColorsGenerator({ dataSets: this.dataSets }, this.dataSets.length);
38166
+ const colors = this.dataSets.map((ds) => colorGenerator.next());
38167
+ this.dataSets = indexes.map((i) => ({
38168
+ backgroundColor: colors[i],
38169
+ ...this.dataSets[i],
38170
+ }));
38171
+ this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
38172
+ dataSets: this.dataSets,
38173
+ });
38174
+ }
38175
+ onDataSeriesRemoved(index) {
38176
+ const colorGenerator = getChartColorsGenerator({ dataSets: this.dataSets }, this.dataSets.length);
38177
+ const colors = this.dataSets.map((ds) => colorGenerator.next());
38178
+ this.dataSets = this.dataSets
38179
+ .map((ds, i) => ({
38180
+ backgroundColor: colors[i],
38181
+ ...ds,
38182
+ }))
38183
+ .filter((_, i) => i !== index);
38184
+ this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
38185
+ dataSets: this.dataSets,
37666
38186
  });
37667
38187
  }
37668
38188
  onDataSeriesConfirmed() {
37669
- this.dataSeriesRanges = spreadRange(this.env.model.getters, this.dataSeriesRanges);
38189
+ this.dataSets = spreadRange(this.env.model.getters, this.dataSets);
37670
38190
  this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
37671
- dataSets: this.dataSeriesRanges,
38191
+ dataSets: this.dataSets,
37672
38192
  });
37673
38193
  }
37674
38194
  getDataSeriesRanges() {
37675
- return this.dataSeriesRanges;
38195
+ return this.dataSets;
37676
38196
  }
37677
38197
  /**
37678
38198
  * Change the local labelRange. The model should be updated when the
@@ -37704,7 +38224,7 @@ stores.inject(MyMetaStore, storeInstance);
37704
38224
  const getters = this.env.model.getters;
37705
38225
  const sheetId = getters.getActiveSheetId();
37706
38226
  const labelRange = createValidRange(getters, sheetId, this.labelRange);
37707
- const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
38227
+ const dataSets = createDataSets(getters, this.dataSets, sheetId, this.props.definition.dataSetsHaveTitle);
37708
38228
  if (dataSets.length) {
37709
38229
  return dataSets[0].dataRange.zone.top + 1;
37710
38230
  }
@@ -37806,157 +38326,6 @@ stores.inject(MyMetaStore, storeInstance);
37806
38326
  };
37807
38327
  }
37808
38328
 
37809
- /**
37810
- * Start listening to pointer events and apply the given callbacks.
37811
- *
37812
- * @returns A function to remove the listeners.
37813
- */
37814
- function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
37815
- const removeListeners = () => {
37816
- window.removeEventListener("pointerdown", onMouseDown);
37817
- window.removeEventListener("pointerup", _onMouseUp);
37818
- window.removeEventListener("dragstart", _onDragStart);
37819
- window.removeEventListener("pointermove", onMouseMove);
37820
- window.removeEventListener("wheel", onMouseMove);
37821
- };
37822
- const _onMouseUp = (ev) => {
37823
- onMouseUp(ev);
37824
- removeListeners();
37825
- };
37826
- function _onDragStart(ev) {
37827
- ev.preventDefault();
37828
- }
37829
- window.addEventListener("pointerdown", onMouseDown);
37830
- window.addEventListener("pointerup", _onMouseUp);
37831
- window.addEventListener("dragstart", _onDragStart);
37832
- window.addEventListener("pointermove", onMouseMove);
37833
- // mouse wheel on window is by default a passive event.
37834
- // preventDefault() is not allowed in passive event handler.
37835
- // https://chromestatus.com/feature/6662647093133312
37836
- window.addEventListener("wheel", onMouseMove, { passive: false });
37837
- return removeListeners;
37838
- }
37839
- /**
37840
- * Function to be used during a pointerdown event, this function allows to
37841
- * perform actions related to the pointermove and pointerup events and adjusts the viewport
37842
- * when the new position related to the pointermove event is outside of it.
37843
- * Among inputs are two callback functions. First intended for actions performed during
37844
- * the pointermove event, it receives as parameters the current position of the pointermove
37845
- * (occurrence of the current column and the current row). Second intended for actions
37846
- * performed during the pointerup event.
37847
- */
37848
- function dragAndDropBeyondTheViewport(env, cbMouseMove, cbMouseUp, only = false) {
37849
- let timeOutId = null;
37850
- let currentEv;
37851
- let previousEv;
37852
- let startingEv;
37853
- let startingX;
37854
- let startingY;
37855
- const getters = env.model.getters;
37856
- const sheetId = getters.getActiveSheetId();
37857
- const position = gridOverlayPosition();
37858
- let colIndex;
37859
- let rowIndex;
37860
- const onMouseDown = (ev) => {
37861
- previousEv = ev;
37862
- startingEv = ev;
37863
- startingX = startingEv.clientX - position.left;
37864
- startingY = startingEv.clientY - position.top;
37865
- };
37866
- const onMouseMove = (ev) => {
37867
- currentEv = ev;
37868
- if (timeOutId) {
37869
- return;
37870
- }
37871
- const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
37872
- let { top, left, bottom, right } = getters.getActiveMainViewport();
37873
- let { scrollX, scrollY } = getters.getActiveSheetDOMScrollInfo();
37874
- const { xSplit, ySplit } = getters.getPaneDivisions(sheetId);
37875
- let canEdgeScroll = false;
37876
- let timeoutDelay = MAX_DELAY;
37877
- const x = currentEv.clientX - position.left;
37878
- colIndex = getters.getColIndex(x);
37879
- if (only !== "vertical") {
37880
- const previousX = previousEv.clientX - position.left;
37881
- const edgeScrollInfoX = getters.getEdgeScrollCol(x, previousX, startingX);
37882
- if (edgeScrollInfoX.canEdgeScroll) {
37883
- canEdgeScroll = true;
37884
- timeoutDelay = Math.min(timeoutDelay, edgeScrollInfoX.delay);
37885
- let newTarget;
37886
- switch (edgeScrollInfoX.direction) {
37887
- case "reset":
37888
- colIndex = xSplit;
37889
- newTarget = xSplit;
37890
- break;
37891
- case 1:
37892
- colIndex = right;
37893
- newTarget = left + 1;
37894
- break;
37895
- case -1:
37896
- colIndex = left - 1;
37897
- while (env.model.getters.isColHidden(sheetId, colIndex)) {
37898
- colIndex--;
37899
- }
37900
- newTarget = colIndex;
37901
- break;
37902
- }
37903
- scrollX = getters.getColDimensions(sheetId, newTarget).start - offsetCorrectionX;
37904
- }
37905
- }
37906
- const y = currentEv.clientY - position.top;
37907
- rowIndex = getters.getRowIndex(y);
37908
- if (only !== "horizontal") {
37909
- const previousY = previousEv.clientY - position.top;
37910
- const edgeScrollInfoY = getters.getEdgeScrollRow(y, previousY, startingY);
37911
- if (edgeScrollInfoY.canEdgeScroll) {
37912
- canEdgeScroll = true;
37913
- timeoutDelay = Math.min(timeoutDelay, edgeScrollInfoY.delay);
37914
- let newTarget;
37915
- switch (edgeScrollInfoY.direction) {
37916
- case "reset":
37917
- rowIndex = ySplit;
37918
- newTarget = ySplit;
37919
- break;
37920
- case 1:
37921
- rowIndex = bottom;
37922
- newTarget = top + edgeScrollInfoY.direction;
37923
- break;
37924
- case -1:
37925
- rowIndex = top - 1;
37926
- while (env.model.getters.isRowHidden(sheetId, rowIndex)) {
37927
- rowIndex--;
37928
- }
37929
- newTarget = rowIndex;
37930
- break;
37931
- }
37932
- scrollY = env.model.getters.getRowDimensions(sheetId, newTarget).start - offsetCorrectionY;
37933
- }
37934
- }
37935
- if (!canEdgeScroll) {
37936
- if (rowIndex === -1) {
37937
- rowIndex = y < 0 ? 0 : getters.getNumberRows(sheetId) - 1;
37938
- }
37939
- if (colIndex === -1 && x < 0) {
37940
- colIndex = x < 0 ? 0 : getters.getNumberCols(sheetId) - 1;
37941
- }
37942
- }
37943
- cbMouseMove(colIndex, rowIndex, currentEv);
37944
- if (canEdgeScroll) {
37945
- env.model.dispatch("SET_VIEWPORT_OFFSET", { offsetX: scrollX, offsetY: scrollY });
37946
- timeOutId = setTimeout(() => {
37947
- timeOutId = null;
37948
- onMouseMove(currentEv);
37949
- }, Math.round(timeoutDelay));
37950
- }
37951
- previousEv = currentEv;
37952
- };
37953
- const onMouseUp = () => {
37954
- clearTimeout(timeOutId);
37955
- cbMouseUp();
37956
- };
37957
- startDnd(onMouseMove, onMouseUp, onMouseDown);
37958
- }
37959
-
37960
38329
  const LINE_VERTICAL_PADDING = 1;
37961
38330
  const PICKER_PADDING = 8;
37962
38331
  const ITEM_BORDER_WIDTH = 1;
@@ -39238,9 +39607,9 @@ stores.inject(MyMetaStore, storeInstance);
39238
39607
  return this.getDataSeriesRanges().slice(0, 1);
39239
39608
  }
39240
39609
  onDataSeriesConfirmed() {
39241
- this.dataSeriesRanges = spreadRange(this.env.model.getters, this.dataSeriesRanges).slice(0, 1);
39610
+ this.dataSets = spreadRange(this.env.model.getters, this.dataSets).slice(0, 1);
39242
39611
  this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
39243
- dataSets: this.dataSeriesRanges,
39612
+ dataSets: this.dataSets,
39244
39613
  });
39245
39614
  }
39246
39615
  getLabelRangeOptions() {
@@ -41098,289 +41467,6 @@ stores.inject(MyMetaStore, storeInstance);
41098
41467
  }
41099
41468
  }
41100
41469
 
41101
- function useDragAndDropListItems() {
41102
- let dndHelper;
41103
- const previousCursor = document.body.style.cursor;
41104
- let cleanupFns = [];
41105
- const cleanUp = () => {
41106
- dndHelper = undefined;
41107
- document.body.style.cursor = previousCursor;
41108
- cleanupFns.forEach((fn) => fn());
41109
- cleanupFns = [];
41110
- };
41111
- const start = (direction, args) => {
41112
- const onChange = () => {
41113
- document.body.style.cursor = "move";
41114
- if (!dndHelper)
41115
- return;
41116
- Object.assign(state.itemsStyle, dndHelper.getItemStyles());
41117
- args.onChange?.();
41118
- };
41119
- state.cancel = () => {
41120
- state.draggedItemId = undefined;
41121
- state.itemsStyle = {};
41122
- document.body.style.cursor = previousCursor;
41123
- args.onCancel?.();
41124
- cleanUp();
41125
- };
41126
- const onDragEnd = (itemId, indexAtEnd) => {
41127
- state.draggedItemId = undefined;
41128
- state.itemsStyle = {};
41129
- document.body.style.cursor = previousCursor;
41130
- args.onDragEnd?.(itemId, indexAtEnd);
41131
- cleanUp();
41132
- };
41133
- document.body.style.cursor = "move";
41134
- state.draggedItemId = args.draggedItemId;
41135
- const container = direction === "horizontal"
41136
- ? new HorizontalContainer(args.containerEl)
41137
- : new VerticalContainer(args.containerEl);
41138
- dndHelper = new DOMDndHelper({
41139
- ...args,
41140
- container,
41141
- onChange,
41142
- onDragEnd,
41143
- onCancel: state.cancel,
41144
- });
41145
- const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
41146
- cleanupFns.push(stopListening);
41147
- const onScroll = dndHelper.onScroll.bind(dndHelper);
41148
- args.containerEl.addEventListener("scroll", onScroll);
41149
- cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
41150
- cleanupFns.push(dndHelper.destroy.bind(dndHelper));
41151
- };
41152
- owl.onWillUnmount(() => {
41153
- cleanUp();
41154
- });
41155
- const state = owl.useState({
41156
- itemsStyle: {},
41157
- draggedItemId: undefined,
41158
- start,
41159
- cancel: () => { },
41160
- });
41161
- return state;
41162
- }
41163
- class DOMDndHelper {
41164
- draggedItemId;
41165
- items;
41166
- container;
41167
- initialMousePosition;
41168
- currentMousePosition;
41169
- initialScroll;
41170
- minPosition;
41171
- maxPosition;
41172
- edgeScrollIntervalId;
41173
- onChange;
41174
- onCancel;
41175
- onDragEnd;
41176
- /**
41177
- * The dead zone is an area in which the pointermove events are ignored.
41178
- *
41179
- * This is useful when swapping the dragged item with a larger item. After the swap,
41180
- * the mouse is still hovering on the item we just swapped with. In this case, we don't want
41181
- * a mouse move to trigger another swap the other way around, so we create a dead zone. We will clear
41182
- * the dead zone when the mouse leaves the swapped item.
41183
- */
41184
- deadZone;
41185
- constructor(args) {
41186
- this.items = args.items.map((item) => ({ ...item, positionAtStart: item.position }));
41187
- this.draggedItemId = args.draggedItemId;
41188
- this.container = args.container;
41189
- this.onChange = args.onChange;
41190
- this.onCancel = args.onCancel;
41191
- this.onDragEnd = args.onDragEnd;
41192
- this.initialMousePosition = args.initialMousePosition;
41193
- this.currentMousePosition = args.initialMousePosition;
41194
- this.initialScroll = this.container.scroll;
41195
- this.minPosition = this.items[0].position;
41196
- this.maxPosition =
41197
- this.items[this.items.length - 1].position + this.items[this.items.length - 1].size;
41198
- }
41199
- getItemStyles() {
41200
- const styles = {};
41201
- for (let item of this.items) {
41202
- styles[item.id] = this.getItemStyle(item.id);
41203
- }
41204
- return styles;
41205
- }
41206
- getItemStyle(itemId) {
41207
- const position = this.container.cssPositionProperty;
41208
- const style = {};
41209
- style.position = "relative";
41210
- style[position] = (this.getItemsPositions()[itemId] || 0) + "px";
41211
- style.transition = `${position} 0.5s`;
41212
- style["pointer-events"] = "none";
41213
- if (this.draggedItemId === itemId) {
41214
- style.transition = `${position} 0s`;
41215
- style["z-index"] = "1000";
41216
- }
41217
- return cssPropertiesToCss(style);
41218
- }
41219
- onScroll() {
41220
- this.moveDraggedItemToPosition(this.currentMousePosition + this.scrollOffset);
41221
- }
41222
- onMouseMove(ev) {
41223
- if (ev.button > 1) {
41224
- this.onCancel();
41225
- return;
41226
- }
41227
- const mousePosition = this.container.getMousePosition(ev);
41228
- this.currentMousePosition = mousePosition;
41229
- if (mousePosition < this.container.start || mousePosition > this.container.end) {
41230
- this.startEdgeScroll(mousePosition < this.container.start ? -1 : 1);
41231
- return;
41232
- }
41233
- else {
41234
- this.stopEdgeScroll();
41235
- }
41236
- this.moveDraggedItemToPosition(mousePosition + this.scrollOffset);
41237
- }
41238
- moveDraggedItemToPosition(position) {
41239
- const hoveredItemIndex = this.getHoveredItemIndex(position, this.items);
41240
- const draggedItemIndex = this.items.findIndex((item) => item.id === this.draggedItemId);
41241
- const draggedItem = this.items[draggedItemIndex];
41242
- if (this.deadZone && this.isInZone(position, this.deadZone)) {
41243
- this.onChange(this.getItemsPositions());
41244
- return;
41245
- }
41246
- else if (this.isInZone(position, {
41247
- start: draggedItem.position,
41248
- end: draggedItem.position + draggedItem.size,
41249
- })) {
41250
- this.deadZone = undefined;
41251
- }
41252
- if (draggedItemIndex === hoveredItemIndex) {
41253
- this.onChange(this.getItemsPositions());
41254
- return;
41255
- }
41256
- const startIndex = Math.min(draggedItemIndex, hoveredItemIndex);
41257
- const endIndex = Math.max(draggedItemIndex, hoveredItemIndex);
41258
- const direction = Math.sign(hoveredItemIndex - draggedItemIndex);
41259
- let draggedItemMoveSize = 0;
41260
- for (let i = startIndex; i <= endIndex; i++) {
41261
- if (i === draggedItemIndex) {
41262
- continue;
41263
- }
41264
- this.items[i].position -= direction * draggedItem.size;
41265
- draggedItemMoveSize += this.items[i].size;
41266
- }
41267
- draggedItem.position += direction * draggedItemMoveSize;
41268
- this.items.sort((item1, item2) => item1.position - item2.position);
41269
- this.deadZone =
41270
- direction > 0
41271
- ? { start: position, end: draggedItem.position }
41272
- : { start: draggedItem.position + draggedItem.size, end: position };
41273
- this.onChange(this.getItemsPositions());
41274
- }
41275
- onMouseUp(ev) {
41276
- if (ev.button !== 0) {
41277
- this.onCancel();
41278
- }
41279
- ev.stopPropagation();
41280
- ev.preventDefault();
41281
- const targetItemIndex = this.items.findIndex((item) => item.id === this.draggedItemId);
41282
- this.onDragEnd(this.draggedItemId, targetItemIndex);
41283
- this.stopEdgeScroll();
41284
- return false;
41285
- }
41286
- startEdgeScroll(direction) {
41287
- if (this.edgeScrollIntervalId)
41288
- return;
41289
- this.edgeScrollIntervalId = window.setInterval(() => {
41290
- const offset = direction * 3;
41291
- this.container.scroll += offset;
41292
- }, 5);
41293
- }
41294
- stopEdgeScroll() {
41295
- window.clearInterval(this.edgeScrollIntervalId);
41296
- this.edgeScrollIntervalId = undefined;
41297
- }
41298
- /**
41299
- * Get the index of the item the given mouse position is inside.
41300
- * If the mouse is outside the container, return the first or last item index.
41301
- */
41302
- getHoveredItemIndex(mousePosition, items) {
41303
- if (mousePosition <= this.minPosition)
41304
- return 0;
41305
- if (mousePosition >= this.maxPosition)
41306
- return items.length - 1;
41307
- return items.findIndex((item) => item.position + item.size >= mousePosition);
41308
- }
41309
- getItemsPositions() {
41310
- const positions = {};
41311
- for (let item of this.items) {
41312
- if (item.id !== this.draggedItemId) {
41313
- positions[item.id] = item.position - item.positionAtStart;
41314
- continue;
41315
- }
41316
- const mouseOffset = this.currentMousePosition - this.initialMousePosition;
41317
- let start = mouseOffset + this.scrollOffset;
41318
- start = Math.max(this.minPosition - item.positionAtStart, start);
41319
- start = Math.min(this.maxPosition - item.positionAtStart - item.size, start);
41320
- positions[item.id] = start;
41321
- }
41322
- return positions;
41323
- }
41324
- isInZone(position, zone) {
41325
- return position >= zone.start && position <= zone.end;
41326
- }
41327
- get scrollOffset() {
41328
- return this.container.scroll - this.initialScroll;
41329
- }
41330
- destroy() {
41331
- this.stopEdgeScroll();
41332
- }
41333
- }
41334
- class ContainerWrapper {
41335
- el;
41336
- constructor(el) {
41337
- this.el = el;
41338
- }
41339
- get containerRect() {
41340
- return this.el.getBoundingClientRect();
41341
- }
41342
- }
41343
- class VerticalContainer extends ContainerWrapper {
41344
- get start() {
41345
- return this.containerRect.top;
41346
- }
41347
- get end() {
41348
- return this.containerRect.bottom;
41349
- }
41350
- get cssPositionProperty() {
41351
- return "top";
41352
- }
41353
- get scroll() {
41354
- return this.el.scrollTop;
41355
- }
41356
- set scroll(scroll) {
41357
- this.el.scrollTop = scroll;
41358
- }
41359
- getMousePosition(ev) {
41360
- return ev.clientY;
41361
- }
41362
- }
41363
- class HorizontalContainer extends ContainerWrapper {
41364
- get start() {
41365
- return this.containerRect.left;
41366
- }
41367
- get end() {
41368
- return this.containerRect.right;
41369
- }
41370
- get cssPositionProperty() {
41371
- return "left";
41372
- }
41373
- get scroll() {
41374
- return this.el.scrollLeft;
41375
- }
41376
- set scroll(scroll) {
41377
- this.el.scrollLeft = scroll;
41378
- }
41379
- getMousePosition(ev) {
41380
- return ev.clientX;
41381
- }
41382
- }
41383
-
41384
41470
  /**
41385
41471
  * Manages an event listener on a ref. Useful for hooks that want to manage
41386
41472
  * event listeners, especially more than one. Prefer using t-on directly in
@@ -46284,7 +46370,7 @@ stores.inject(MyMetaStore, storeInstance);
46284
46370
  onIterationEndEvaluation: (pivot) => pivot.markAsDirtyForEvaluation(),
46285
46371
  dateGranularities: [...dateGranularities],
46286
46372
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
46287
- isMeasureCandidate: (field) => !["datetime", "boolean"].includes(field.type),
46373
+ isMeasureCandidate: (field) => field.type !== "boolean",
46288
46374
  isGroupable: () => true,
46289
46375
  });
46290
46376
 
@@ -46502,8 +46588,11 @@ stores.inject(MyMetaStore, storeInstance);
46502
46588
  };
46503
46589
  }
46504
46590
  getUnusedGranularities(fields, definition) {
46505
- const { columns, rows } = definition;
46506
- const dateFields = columns.concat(rows).filter((dimension) => {
46591
+ const { columns, rows, measures } = definition;
46592
+ const dateFields = columns
46593
+ .concat(rows)
46594
+ .concat(measures)
46595
+ .filter((dimension) => {
46507
46596
  const fieldType = fields[dimension.fieldName]?.type;
46508
46597
  return fieldType === "date" || fieldType === "datetime";
46509
46598
  });
@@ -48775,7 +48864,7 @@ stores.inject(MyMetaStore, storeInstance);
48775
48864
  return;
48776
48865
  }
48777
48866
  const sheetId = this.env.model.getters.getActiveSheetId();
48778
- const zone = this.env.model.getters.getSelectedZone();
48867
+ const zone = positionToZone(this.env.model.getters.getSelection().anchor.cell);
48779
48868
  const rect = this.env.model.getters.getVisibleRect(zone);
48780
48869
  if (!deepEquals(rect, this.rect) || sheetId !== this.composerStore.currentEditedCell.sheetId) {
48781
48870
  this.isCellReferenceVisible = true;
@@ -50611,13 +50700,23 @@ stores.inject(MyMetaStore, storeInstance);
50611
50700
  drawLayer(renderingContext, layer) {
50612
50701
  switch (layer) {
50613
50702
  case "Background":
50614
- const boxes = this.getGridBoxes();
50615
- this.drawBackground(renderingContext, boxes);
50616
- this.drawOverflowingCellBackground(renderingContext, boxes);
50617
- this.drawCellBackground(renderingContext, boxes);
50618
- this.drawBorders(renderingContext, boxes);
50619
- this.drawTexts(renderingContext, boxes);
50620
- this.drawIcon(renderingContext, boxes);
50703
+ this.drawGlobalBackground(renderingContext);
50704
+ for (const zone of this.getters.getAllActiveViewportsZones()) {
50705
+ const { ctx } = renderingContext;
50706
+ ctx.save();
50707
+ ctx.beginPath();
50708
+ const rect = this.getters.getVisibleRect(zone);
50709
+ ctx.rect(rect.x, rect.y, rect.width, rect.height);
50710
+ ctx.clip();
50711
+ const boxes = this.getGridBoxes(zone);
50712
+ this.drawBackground(renderingContext, boxes);
50713
+ this.drawOverflowingCellBackground(renderingContext, boxes);
50714
+ this.drawCellBackground(renderingContext, boxes);
50715
+ this.drawBorders(renderingContext, boxes);
50716
+ this.drawTexts(renderingContext, boxes);
50717
+ this.drawIcon(renderingContext, boxes);
50718
+ ctx.restore();
50719
+ }
50621
50720
  this.drawFrozenPanes(renderingContext);
50622
50721
  break;
50623
50722
  case "Headers":
@@ -50628,12 +50727,15 @@ stores.inject(MyMetaStore, storeInstance);
50628
50727
  break;
50629
50728
  }
50630
50729
  }
50631
- drawBackground(renderingContext, boxes) {
50632
- const { ctx, thinLineWidth } = renderingContext;
50730
+ drawGlobalBackground(renderingContext) {
50731
+ const { ctx } = renderingContext;
50633
50732
  const { width, height } = this.getters.getSheetViewDimensionWithHeaders();
50634
50733
  // white background
50635
50734
  ctx.fillStyle = "#ffffff";
50636
50735
  ctx.fillRect(0, 0, width + CANVAS_SHIFT, height + CANVAS_SHIFT);
50736
+ }
50737
+ drawBackground(renderingContext, boxes) {
50738
+ const { ctx, thinLineWidth } = renderingContext;
50637
50739
  const areGridLinesVisible = !this.getters.isDashboard() &&
50638
50740
  this.getters.getGridLinesVisibility(this.getters.getActiveSheetId());
50639
50741
  const inset = areGridLinesVisible ? 0.1 * thinLineWidth : 0;
@@ -51064,7 +51166,7 @@ stores.inject(MyMetaStore, storeInstance);
51064
51166
  const position = { sheetId, col, row };
51065
51167
  const cell = this.getters.getEvaluatedCell(position);
51066
51168
  const showFormula = this.getters.shouldShowFormulas();
51067
- const { x, y, width, height } = this.getters.getVisibleRect(zone);
51169
+ const { x, y, width, height } = this.getters.getRect(zone);
51068
51170
  const { verticalAlign } = this.getters.getCellStyle(position);
51069
51171
  let style = this.getters.getCellComputedStyle(position);
51070
51172
  if (this.fingerprints.isEnabled) {
@@ -51189,12 +51291,16 @@ stores.inject(MyMetaStore, storeInstance);
51189
51291
  }
51190
51292
  return box;
51191
51293
  }
51192
- getGridBoxes() {
51294
+ getGridBoxes(zone) {
51193
51295
  const boxes = [];
51194
- const visibleCols = this.getters.getSheetViewVisibleCols();
51296
+ const visibleCols = this.getters
51297
+ .getSheetViewVisibleCols()
51298
+ .filter((col) => col >= zone.left && col <= zone.right);
51195
51299
  const left = visibleCols[0];
51196
51300
  const right = visibleCols[visibleCols.length - 1];
51197
- const visibleRows = this.getters.getSheetViewVisibleRows();
51301
+ const visibleRows = this.getters
51302
+ .getSheetViewVisibleRows()
51303
+ .filter((row) => row >= zone.top && row <= zone.bottom);
51198
51304
  const top = visibleRows[0];
51199
51305
  const bottom = visibleRows[visibleRows.length - 1];
51200
51306
  const viewport = { left, right, top, bottom };
@@ -53426,7 +53532,7 @@ stores.inject(MyMetaStore, storeInstance);
53426
53532
  /*
53427
53533
  * Reconstructs the original formula string based on new dependencies
53428
53534
  */
53429
- getFormulaString(sheetId, tokens, dependencies, useFixedReference = false) {
53535
+ getFormulaString(sheetId, tokens, dependencies, useBoundedReference = false) {
53430
53536
  if (!dependencies.length) {
53431
53537
  return concat(tokens.map((token) => token.value));
53432
53538
  }
@@ -53434,7 +53540,7 @@ stores.inject(MyMetaStore, storeInstance);
53434
53540
  return concat(tokens.map((token) => {
53435
53541
  if (token.type === "REFERENCE") {
53436
53542
  const range = dependencies[rangeIndex++];
53437
- return this.getters.getRangeString(range, sheetId, { useFixedReference });
53543
+ return this.getters.getRangeString(range, sheetId, { useBoundedReference });
53438
53544
  }
53439
53545
  return token.value;
53440
53546
  }));
@@ -53714,7 +53820,7 @@ stores.inject(MyMetaStore, storeInstance);
53714
53820
  if (token.type === "REFERENCE") {
53715
53821
  const index = rangeIndex++;
53716
53822
  return this.getRangeString(this.compiledFormula.dependencies[index], this.sheetId, {
53717
- useFixedReference: true,
53823
+ useBoundedReference: true,
53718
53824
  });
53719
53825
  }
53720
53826
  return token.value;
@@ -54051,7 +54157,7 @@ stores.inject(MyMetaStore, storeInstance);
54051
54157
  if (data.sheets) {
54052
54158
  for (let sheet of data.sheets) {
54053
54159
  if (this.cfRules[sheet.id]) {
54054
- sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useFixedReference: true }));
54160
+ sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useBoundedReference: true }));
54055
54161
  }
54056
54162
  }
54057
54163
  }
@@ -54120,9 +54226,9 @@ stores.inject(MyMetaStore, storeInstance);
54120
54226
  // ---------------------------------------------------------------------------
54121
54227
  // Private
54122
54228
  // ---------------------------------------------------------------------------
54123
- mapToConditionalFormat(sheetId, cf, { useFixedReference } = { useFixedReference: false }) {
54229
+ mapToConditionalFormat(sheetId, cf, { useBoundedReference } = { useBoundedReference: false }) {
54124
54230
  const ranges = cf.ranges.map((range) => {
54125
- return this.getters.getRangeString(range, sheetId, { useFixedReference });
54231
+ return this.getters.getRangeString(range, sheetId, { useBoundedReference });
54126
54232
  });
54127
54233
  if (cf.rule.type !== "DataBarRule") {
54128
54234
  return {
@@ -54137,7 +54243,7 @@ stores.inject(MyMetaStore, storeInstance);
54137
54243
  ...cf.rule,
54138
54244
  rangeValues: cf.rule.rangeValues &&
54139
54245
  this.getters.getRangeString(cf.rule.rangeValues, sheetId, {
54140
- useFixedReference,
54246
+ useBoundedReference,
54141
54247
  }),
54142
54248
  },
54143
54249
  ranges,
@@ -54580,7 +54686,7 @@ stores.inject(MyMetaStore, storeInstance);
54580
54686
  for (const rule of this.rules[sheet.id]) {
54581
54687
  sheet.dataValidationRules.push({
54582
54688
  ...rule,
54583
- ranges: rule.ranges.map((range) => this.getters.getRangeString(range, sheet.id, { useFixedReference: true })),
54689
+ ranges: rule.ranges.map((range) => this.getters.getRangeString(range, sheet.id, { useBoundedReference: true })),
54584
54690
  });
54585
54691
  }
54586
54692
  }
@@ -56002,9 +56108,9 @@ stores.inject(MyMetaStore, storeInstance);
56002
56108
  * @param range the range (received from getRangeFromXC or getRangeFromZone)
56003
56109
  * @param forSheetId the id of the sheet where the range string is supposed to be used.
56004
56110
  * @param options
56005
- * @param options.useFixedReference if true, the range will be returned with fixed row and column
56111
+ * @param options.useBoundedReference if true, the range will be returned with fixed row and column
56006
56112
  */
56007
- getRangeString(range, forSheetId, options = { useFixedReference: false }) {
56113
+ getRangeString(range, forSheetId, options = { useBoundedReference: false }) {
56008
56114
  if (!range) {
56009
56115
  return CellErrorType.InvalidReference;
56010
56116
  }
@@ -56107,13 +56213,13 @@ stores.inject(MyMetaStore, storeInstance);
56107
56213
  /**
56108
56214
  * Get a Xc string that represent a part of a range
56109
56215
  */
56110
- getRangePartString(range, part, options = { useFixedReference: false }) {
56216
+ getRangePartString(range, part, options = { useBoundedReference: false }) {
56111
56217
  const colFixed = range.parts && range.parts[part]?.colFixed ? "$" : "";
56112
56218
  const col = part === 0 ? numberToLetters(range.zone.left) : numberToLetters(range.zone.right);
56113
56219
  const rowFixed = range.parts && range.parts[part]?.rowFixed ? "$" : "";
56114
56220
  const row = part === 0 ? String(range.zone.top + 1) : String(range.zone.bottom + 1);
56115
56221
  let str = "";
56116
- if (range.isFullCol && !options.useFixedReference) {
56222
+ if (range.isFullCol && !options.useBoundedReference) {
56117
56223
  if (part === 0 && range.unboundedZone.hasHeader) {
56118
56224
  str = colFixed + col + rowFixed + row;
56119
56225
  }
@@ -56121,7 +56227,7 @@ stores.inject(MyMetaStore, storeInstance);
56121
56227
  str = colFixed + col;
56122
56228
  }
56123
56229
  }
56124
- else if (range.isFullRow && !options.useFixedReference) {
56230
+ else if (range.isFullRow && !options.useBoundedReference) {
56125
56231
  if (part === 0 && range.unboundedZone.hasHeader) {
56126
56232
  str = colFixed + col + rowFixed + row;
56127
56233
  }
@@ -66847,8 +66953,12 @@ stores.inject(MyMetaStore, storeInstance);
66847
66953
  },
66848
66954
  ];
66849
66955
  handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
66956
+ const selection = pasteTarget[0];
66957
+ const col = selection.left;
66958
+ const row = selection.top;
66959
+ this.setSelectionMixin({ zone: selection, cell: { col, row } }, [selection]);
66850
66960
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
66851
- let currentIndex = cmd.base;
66961
+ let currentIndex = isBasedBefore ? cmd.base : cmd.base + 1;
66852
66962
  const resizingGroups = {};
66853
66963
  for (const element of toRemove) {
66854
66964
  const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
@@ -67139,22 +67249,33 @@ stores.inject(MyMetaStore, storeInstance);
67139
67249
  }
67140
67250
  /**
67141
67251
  *
67142
- * @param zone
67143
- * @returns Computes the absolute coordinate of a given zone inside the viewport
67252
+ * Computes the visible coordinates & dimensions of a given zone inside the viewport
67253
+ *
67144
67254
  */
67145
- getRect(zone) {
67255
+ getVisibleRect(zone) {
67146
67256
  const targetZone = intersection(zone, this);
67147
67257
  if (targetZone) {
67148
67258
  const x = this.getters.getColRowOffset("COL", this.left, targetZone.left) + this.offsetCorrectionX;
67149
67259
  const y = this.getters.getColRowOffset("ROW", this.top, targetZone.top) + this.offsetCorrectionY;
67150
67260
  const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
67151
67261
  const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
67152
- return {
67153
- x,
67154
- y,
67155
- width,
67156
- height,
67157
- };
67262
+ return { x, y, width, height };
67263
+ }
67264
+ return undefined;
67265
+ }
67266
+ /**
67267
+ *
67268
+ * @returns Computes the absolute coordinates & dimensions of a given zone inside the viewport
67269
+ *
67270
+ */
67271
+ getFullRect(zone) {
67272
+ const targetZone = intersection(zone, this);
67273
+ if (targetZone) {
67274
+ const x = this.getters.getColRowOffset("COL", this.left, zone.left) + this.offsetCorrectionX;
67275
+ const y = this.getters.getColRowOffset("ROW", this.top, zone.top) + this.offsetCorrectionY;
67276
+ const width = this.getters.getColRowOffset("COL", zone.left, zone.right + 1);
67277
+ const height = this.getters.getColRowOffset("ROW", zone.top, zone.bottom + 1);
67278
+ return { x, y, width, height };
67158
67279
  }
67159
67280
  return undefined;
67160
67281
  }
@@ -67324,6 +67445,8 @@ stores.inject(MyMetaStore, storeInstance);
67324
67445
  "isPositionVisible",
67325
67446
  "getColDimensionsInViewport",
67326
67447
  "getRowDimensionsInViewport",
67448
+ "getAllActiveViewportsZones",
67449
+ "getRect",
67327
67450
  ];
67328
67451
  viewports = {};
67329
67452
  /**
@@ -67707,16 +67830,27 @@ stores.inject(MyMetaStore, storeInstance);
67707
67830
  getVisibleRectWithoutHeaders(zone) {
67708
67831
  const sheetId = this.getters.getActiveSheetId();
67709
67832
  const viewportRects = this.getSubViewports(sheetId)
67710
- .map((viewport) => viewport.getRect(zone))
67833
+ .map((viewport) => viewport.getVisibleRect(zone))
67711
67834
  .filter(isDefined);
67712
67835
  if (viewportRects.length === 0) {
67713
67836
  return { x: 0, y: 0, width: 0, height: 0 };
67714
67837
  }
67715
- const x = Math.min(...viewportRects.map((rect) => rect.x));
67716
- const y = Math.min(...viewportRects.map((rect) => rect.y));
67717
- const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
67718
- const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
67719
- return { x, y, width, height };
67838
+ return this.recomposeRect(viewportRects);
67839
+ }
67840
+ /**
67841
+ * Computes the actual size and position (:Rect) of the zone on the canvas
67842
+ * regardless of the viewport dimensions.
67843
+ */
67844
+ getRect(zone) {
67845
+ const sheetId = this.getters.getActiveSheetId();
67846
+ const viewportRects = this.getSubViewports(sheetId)
67847
+ .map((viewport) => viewport.getFullRect(zone))
67848
+ .filter(isDefined);
67849
+ if (viewportRects.length === 0) {
67850
+ return { x: 0, y: 0, width: 0, height: 0 };
67851
+ }
67852
+ const rect = this.recomposeRect(viewportRects);
67853
+ return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
67720
67854
  }
67721
67855
  /**
67722
67856
  * Returns the position of the MainViewport relatively to the start of the grid (without headers)
@@ -67760,6 +67894,10 @@ stores.inject(MyMetaStore, storeInstance);
67760
67894
  end: start + (isRowHidden ? 0 : size),
67761
67895
  };
67762
67896
  }
67897
+ getAllActiveViewportsZones() {
67898
+ const sheetId = this.getters.getActiveSheetId();
67899
+ return this.getSubViewports(sheetId);
67900
+ }
67763
67901
  // ---------------------------------------------------------------------------
67764
67902
  // Private
67765
67903
  // ---------------------------------------------------------------------------
@@ -67950,6 +68088,13 @@ stores.inject(MyMetaStore, storeInstance);
67950
68088
  const height = this.sheetViewHeight + this.gridOffsetY;
67951
68089
  return { xRatio: offsetCorrectionX / width, yRatio: offsetCorrectionY / height };
67952
68090
  }
68091
+ recomposeRect(viewportRects) {
68092
+ const x = Math.min(...viewportRects.map((rect) => rect.x));
68093
+ const y = Math.min(...viewportRects.map((rect) => rect.y));
68094
+ const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
68095
+ const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
68096
+ return { x, y, width, height };
68097
+ }
67953
68098
  }
67954
68099
 
67955
68100
  class HeaderPositionsUIPlugin extends UIPlugin {
@@ -69791,6 +69936,13 @@ stores.inject(MyMetaStore, storeInstance);
69791
69936
  currentStyle: DEFAULT_BORDER_DESC.style,
69792
69937
  currentPosition: undefined,
69793
69938
  });
69939
+ setup() {
69940
+ owl.onWillUpdateProps((newProps) => {
69941
+ if (!newProps.showBorderEditor) {
69942
+ this.state.currentPosition = undefined;
69943
+ }
69944
+ });
69945
+ }
69794
69946
  get borderEditorAnchorRect() {
69795
69947
  const button = this.borderEditorButtonRef.el;
69796
69948
  const buttonRect = button.getBoundingClientRect();
@@ -75102,9 +75254,9 @@ stores.inject(MyMetaStore, storeInstance);
75102
75254
  exports.tokenize = tokenize;
75103
75255
 
75104
75256
 
75105
- __info__.version = "18.2.0-alpha.2";
75106
- __info__.date = "2025-01-15T08:06:32.137Z";
75107
- __info__.hash = "4f96c47";
75257
+ __info__.version = "18.2.0-alpha.3";
75258
+ __info__.date = "2025-01-27T10:07:28.716Z";
75259
+ __info__.hash = "63a13e5";
75108
75260
 
75109
75261
 
75110
75262
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);