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