@odoo/o-spreadsheet 17.3.0-alpha.3 → 17.3.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.3.0-alpha.3
7
- * @date 2024-04-10T12:28:23.658Z
8
- * @hash 80b5056
6
+ * @version 17.3.0-alpha.4
7
+ * @date 2024-04-15T11:02:51.551Z
8
+ * @hash a32a1df
9
9
  */
10
10
 
11
11
  (function (exports, owl) {
@@ -38,6 +38,9 @@
38
38
  const FROZEN_PANE_HEADER_BORDER_COLOR = "#BCBCBC";
39
39
  const FROZEN_PANE_BORDER_COLOR = "#DADFE8";
40
40
  const COMPOSER_ASSISTANT_COLOR = "#9B359B";
41
+ const CHART_WATERFALL_POSITIVE_COLOR = "#006FBE";
42
+ const CHART_WATERFALL_NEGATIVE_COLOR = "#E40000";
43
+ const CHART_WATERFALL_SUBTOTAL_COLOR = "#AAAAAA";
41
44
  // Color picker defaults as upper case HEX to match `toHex`helper
42
45
  const COLOR_PICKER_DEFAULTS = [
43
46
  "#000000",
@@ -2121,6 +2124,7 @@
2121
2124
  CommandResult["NoChanges"] = "NoChanges";
2122
2125
  CommandResult["InvalidInputId"] = "InvalidInputId";
2123
2126
  CommandResult["SheetIsHidden"] = "SheetIsHidden";
2127
+ CommandResult["InvalidTableResize"] = "InvalidTableResize";
2124
2128
  })(exports.CommandResult || (exports.CommandResult = {}));
2125
2129
 
2126
2130
  const PLAIN_TEXT_FORMAT = "@"; // see OpenXML spec §18.8.31
@@ -2518,6 +2522,15 @@
2518
2522
  }
2519
2523
  return generateMatrix(matrix.length, matrix[0].length, (col, row) => fn(matrix[col][row]));
2520
2524
  }
2525
+ function matrixForEach(matrix, fn) {
2526
+ const numberOfCols = matrix.length;
2527
+ const numberOfRows = matrix[0]?.length ?? 0;
2528
+ for (let col = 0; col < numberOfCols; col++) {
2529
+ for (let row = 0; row < numberOfRows; row++) {
2530
+ fn(matrix[col][row]);
2531
+ }
2532
+ }
2533
+ }
2521
2534
  function transposeMatrix(matrix) {
2522
2535
  if (!matrix.length) {
2523
2536
  return [];
@@ -9152,6 +9165,62 @@ stores.inject(MyMetaStore, storeInstance);
9152
9165
  }
9153
9166
  }
9154
9167
 
9168
+ /** This is a chartJS plugin that will draw connector lines between the bars of a Waterfall chart */
9169
+ const waterfallLinesPlugin = {
9170
+ id: "waterfallLinesPlugin",
9171
+ beforeDraw(chart, args, options) {
9172
+ if (!options.showConnectorLines) {
9173
+ return;
9174
+ }
9175
+ // Note: private properties are not in the typing of chartJS (and some of the existing types are missing properties)
9176
+ // so we don't type anything in this file
9177
+ const drawData = chart._metasets?.[0]?.data;
9178
+ if (!drawData) {
9179
+ return;
9180
+ }
9181
+ const ctx = chart.ctx;
9182
+ ctx.save();
9183
+ ctx.setLineDash([3, 2]);
9184
+ for (let i = 0; i < drawData.length; i++) {
9185
+ const bar = drawData[i];
9186
+ if (bar.height === 0) {
9187
+ continue;
9188
+ }
9189
+ const nextBar = getNextNonEmptyBar(drawData, i);
9190
+ if (!nextBar) {
9191
+ break;
9192
+ }
9193
+ const rect = getBarElementRect(bar);
9194
+ const nextBarRect = getBarElementRect(nextBar);
9195
+ const rawBarValues = bar.$context.raw;
9196
+ const value = rawBarValues[1] - rawBarValues[0];
9197
+ const lineY = Math.round(value < 0 ? rect.bottom - 1 : rect.top);
9198
+ const lineStart = Math.round(rect.right);
9199
+ const lineEnd = Math.round(nextBarRect.left);
9200
+ ctx.strokeStyle = "#999";
9201
+ ctx.beginPath();
9202
+ ctx.moveTo(lineStart + 1, lineY + 0.5);
9203
+ ctx.lineTo(lineEnd, lineY + 0.5);
9204
+ ctx.stroke();
9205
+ }
9206
+ ctx.restore();
9207
+ },
9208
+ };
9209
+ function getBarElementRect(bar) {
9210
+ const flipped = bar.base < bar.y; // Bar are flipped for negative values in the dataset
9211
+ return {
9212
+ left: bar.x - bar.width / 2,
9213
+ right: bar.x + bar.width / 2,
9214
+ bottom: flipped ? bar.base + bar.height : bar.y + bar.height,
9215
+ top: flipped ? bar.base : bar.y,
9216
+ };
9217
+ }
9218
+ function getNextNonEmptyBar(bars, startIndex) {
9219
+ return bars.find((bar, i) => i > startIndex && bar.height !== 0);
9220
+ }
9221
+
9222
+ // @ts-ignore
9223
+ window.Chart?.register(waterfallLinesPlugin);
9155
9224
  class ChartJsComponent extends owl.Component {
9156
9225
  static template = "o-spreadsheet-ChartJsComponent";
9157
9226
  static props = {
@@ -9196,10 +9265,7 @@ stores.inject(MyMetaStore, storeInstance);
9196
9265
  else {
9197
9266
  this.chart.data.datasets = [];
9198
9267
  }
9199
- this.chart.config.options.plugins.tooltip = chartData.options.plugins.tooltip;
9200
- this.chart.config.options.plugins.legend = chartData.options.plugins.legend;
9201
- this.chart.config.options.scales = chartData.options?.scales;
9202
- // ?
9268
+ this.chart.config.options = chartData.options;
9203
9269
  this.chart.update("active");
9204
9270
  }
9205
9271
  }
@@ -18824,7 +18890,7 @@ stores.inject(MyMetaStore, storeInstance);
18824
18890
  }
18825
18891
  const descr = addMetaInfoFromArg(addDescr);
18826
18892
  validateArguments(descr.args);
18827
- this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr)), name);
18893
+ this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr), name), name);
18828
18894
  super.add(name, descr);
18829
18895
  return this;
18830
18896
  }
@@ -18863,9 +18929,7 @@ stores.inject(MyMetaStore, storeInstance);
18863
18929
  // so we fallback to a generic error
18864
18930
  if (hasStringValue(e) && isEvaluationError(e.value)) {
18865
18931
  if (hasStringMessage(e)) {
18866
- if (e.message?.includes("[[FUNCTION_NAME]]")) {
18867
- e.message = e.message.replace("[[FUNCTION_NAME]]", functionName);
18868
- }
18932
+ replaceFunctionNamePlaceholder(e, functionName);
18869
18933
  }
18870
18934
  return e;
18871
18935
  }
@@ -18880,21 +18944,29 @@ stores.inject(MyMetaStore, storeInstance);
18880
18944
  return (obj?.message !== undefined &&
18881
18945
  typeof obj.message === "string");
18882
18946
  }
18883
- function addResultHandling(compute) {
18884
- return function (...args) {
18947
+ function addResultHandling(compute, functionName) {
18948
+ return function computeWithResultHandling(...args) {
18885
18949
  const result = compute.apply(this, args);
18886
18950
  if (!isMatrix(result)) {
18887
18951
  if (typeof result === "object" && result !== null && "value" in result) {
18952
+ replaceFunctionNamePlaceholder(result, functionName);
18888
18953
  return result;
18889
18954
  }
18890
18955
  return { value: result };
18891
18956
  }
18892
18957
  if (typeof result[0][0] === "object" && result[0][0] !== null && "value" in result[0][0]) {
18958
+ matrixForEach(result, (result) => replaceFunctionNamePlaceholder(result, functionName));
18893
18959
  return result;
18894
18960
  }
18895
18961
  return matrixMap(result, (row) => ({ value: row }));
18896
18962
  };
18897
18963
  }
18964
+ function replaceFunctionNamePlaceholder(fPayload, functionName) {
18965
+ // for performance reasons: change in place and only if needed
18966
+ if (fPayload.message?.includes("[[FUNCTION_NAME]]")) {
18967
+ fPayload.message = fPayload.message.replace("[[FUNCTION_NAME]]", functionName);
18968
+ }
18969
+ }
18898
18970
  const functionRegistry = new FunctionRegistry();
18899
18971
  for (let category of categories) {
18900
18972
  const fns = category.functions;
@@ -21237,6 +21309,263 @@ stores.inject(MyMetaStore, storeInstance);
21237
21309
  return { chartJsConfig, background };
21238
21310
  }
21239
21311
 
21312
+ class WaterfallChart extends AbstractChart {
21313
+ dataSets;
21314
+ labelRange;
21315
+ background;
21316
+ verticalAxisPosition;
21317
+ legendPosition;
21318
+ aggregated;
21319
+ type = "waterfall";
21320
+ dataSetsHaveTitle;
21321
+ showSubTotals;
21322
+ firstValueAsSubtotal;
21323
+ showConnectorLines;
21324
+ positiveValuesColor;
21325
+ negativeValuesColor;
21326
+ subTotalValuesColor;
21327
+ constructor(definition, sheetId, getters) {
21328
+ super(definition, sheetId, getters);
21329
+ this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
21330
+ this.labelRange = createRange(getters, sheetId, definition.labelRange);
21331
+ this.background = definition.background;
21332
+ this.verticalAxisPosition = definition.verticalAxisPosition;
21333
+ this.legendPosition = definition.legendPosition;
21334
+ this.aggregated = definition.aggregated;
21335
+ this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
21336
+ this.showSubTotals = definition.showSubTotals;
21337
+ this.showConnectorLines = definition.showConnectorLines;
21338
+ this.positiveValuesColor = definition.positiveValuesColor;
21339
+ this.negativeValuesColor = definition.negativeValuesColor;
21340
+ this.subTotalValuesColor = definition.subTotalValuesColor;
21341
+ this.firstValueAsSubtotal = definition.firstValueAsSubtotal;
21342
+ }
21343
+ static transformDefinition(definition, executed) {
21344
+ return transformChartDefinitionWithDataSetsWithZone(definition, executed);
21345
+ }
21346
+ static validateChartDefinition(validator, definition) {
21347
+ return validator.checkValidations(definition, checkDataset, checkLabelRange);
21348
+ }
21349
+ static getDefinitionFromContextCreation(context) {
21350
+ return {
21351
+ background: context.background,
21352
+ dataSets: context.range ? context.range : [],
21353
+ dataSetsHaveTitle: false,
21354
+ aggregated: context.aggregated ?? false,
21355
+ legendPosition: "top",
21356
+ title: context.title || "",
21357
+ type: "waterfall",
21358
+ verticalAxisPosition: "left",
21359
+ labelRange: context.auxiliaryRange || undefined,
21360
+ showSubTotals: true,
21361
+ showConnectorLines: true,
21362
+ firstValueAsSubtotal: false,
21363
+ };
21364
+ }
21365
+ getContextCreation() {
21366
+ return {
21367
+ background: this.background,
21368
+ title: this.title,
21369
+ range: this.dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, this.sheetId)),
21370
+ auxiliaryRange: this.labelRange
21371
+ ? this.getters.getRangeString(this.labelRange, this.sheetId)
21372
+ : undefined,
21373
+ aggregated: this.aggregated,
21374
+ };
21375
+ }
21376
+ copyForSheetId(sheetId) {
21377
+ const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
21378
+ const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
21379
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
21380
+ return new WaterfallChart(definition, sheetId, this.getters);
21381
+ }
21382
+ copyInSheetId(sheetId) {
21383
+ const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
21384
+ return new WaterfallChart(definition, sheetId, this.getters);
21385
+ }
21386
+ getDefinition() {
21387
+ return this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange);
21388
+ }
21389
+ getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
21390
+ return {
21391
+ type: "waterfall",
21392
+ dataSetsHaveTitle: dataSets.length ? Boolean(dataSets[0].labelCell) : false,
21393
+ background: this.background,
21394
+ dataSets: dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, targetSheetId || this.sheetId)),
21395
+ legendPosition: this.legendPosition,
21396
+ verticalAxisPosition: this.verticalAxisPosition,
21397
+ labelRange: labelRange
21398
+ ? this.getters.getRangeString(labelRange, targetSheetId || this.sheetId)
21399
+ : undefined,
21400
+ title: this.title,
21401
+ aggregated: this.aggregated,
21402
+ showSubTotals: this.showSubTotals,
21403
+ showConnectorLines: this.showConnectorLines,
21404
+ positiveValuesColor: this.positiveValuesColor,
21405
+ negativeValuesColor: this.negativeValuesColor,
21406
+ subTotalValuesColor: this.subTotalValuesColor,
21407
+ firstValueAsSubtotal: this.firstValueAsSubtotal,
21408
+ };
21409
+ }
21410
+ getDefinitionForExcel() {
21411
+ // TODO: implement export excel
21412
+ return undefined;
21413
+ }
21414
+ updateRanges(applyChange) {
21415
+ const { dataSets, labelRange, isStale } = updateChartRangesWithDataSets(this.getters, applyChange, this.dataSets, this.labelRange);
21416
+ if (!isStale) {
21417
+ return this;
21418
+ }
21419
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange);
21420
+ return new WaterfallChart(definition, this.sheetId, this.getters);
21421
+ }
21422
+ }
21423
+ function getWaterfallConfiguration(chart, labels, dataSeriesLabels, localeFormat) {
21424
+ const { locale, format } = localeFormat;
21425
+ const fontColor = chartFontColor(chart.background);
21426
+ const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
21427
+ const negativeColor = chart.negativeValuesColor || CHART_WATERFALL_NEGATIVE_COLOR;
21428
+ const positiveColor = chart.positiveValuesColor || CHART_WATERFALL_POSITIVE_COLOR;
21429
+ const subTotalColor = chart.subTotalValuesColor || CHART_WATERFALL_SUBTOTAL_COLOR;
21430
+ const legend = {
21431
+ labels: {
21432
+ generateLabels: () => {
21433
+ const legendValues = [
21434
+ { text: _t("Positive values"), fontColor, fillStyle: positiveColor },
21435
+ { text: _t("Negative values"), fontColor, fillStyle: negativeColor },
21436
+ ];
21437
+ if (chart.showSubTotals || chart.firstValueAsSubtotal) {
21438
+ legendValues.push({
21439
+ text: _t("Subtotals"),
21440
+ fontColor,
21441
+ fillStyle: subTotalColor,
21442
+ });
21443
+ }
21444
+ return legendValues;
21445
+ },
21446
+ },
21447
+ };
21448
+ if (chart.legendPosition === "none") {
21449
+ legend.display = false;
21450
+ }
21451
+ else {
21452
+ legend.position = chart.legendPosition;
21453
+ }
21454
+ config.options.plugins.legend = { ...config.options.plugins?.legend, ...legend };
21455
+ config.options.layout = {
21456
+ padding: { left: 20, right: 20, top: chart.title ? 10 : 25, bottom: 10 },
21457
+ };
21458
+ config.options.scales = {
21459
+ x: {
21460
+ ticks: {
21461
+ padding: 5,
21462
+ color: fontColor,
21463
+ },
21464
+ grid: {
21465
+ display: false,
21466
+ },
21467
+ },
21468
+ y: {
21469
+ position: chart.verticalAxisPosition,
21470
+ ticks: {
21471
+ color: fontColor,
21472
+ callback: (value) => {
21473
+ value = Number(value);
21474
+ if (isNaN(value))
21475
+ return value;
21476
+ return formatValue(value, {
21477
+ locale,
21478
+ format: !format && Math.abs(value) > 1000 ? "#,##" : format,
21479
+ });
21480
+ },
21481
+ },
21482
+ grid: {
21483
+ lineWidth: (context) => {
21484
+ return context.tick.value === 0 ? 2 : 1;
21485
+ },
21486
+ },
21487
+ },
21488
+ };
21489
+ config.options.plugins.tooltip = {
21490
+ callbacks: {
21491
+ label: function (tooltipItem) {
21492
+ const [lastValue, currentValue] = tooltipItem.raw;
21493
+ const yLabel = currentValue - lastValue;
21494
+ const dataSeriesIndex = Math.floor(tooltipItem.dataIndex / labels.length);
21495
+ const dataSeriesLabel = dataSeriesLabels[dataSeriesIndex];
21496
+ const toolTipFormat = !format && Math.abs(yLabel) > 1000 ? "#,##" : format;
21497
+ const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
21498
+ return dataSeriesLabel ? `${dataSeriesLabel}: ${yLabelStr}` : yLabelStr;
21499
+ },
21500
+ },
21501
+ };
21502
+ config.options.plugins.waterfallLinesPlugin = { showConnectorLines: chart.showConnectorLines };
21503
+ return config;
21504
+ }
21505
+ function createWaterfallChartRuntime(chart, getters) {
21506
+ const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
21507
+ let labels = labelValues.formattedValues;
21508
+ let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
21509
+ if (chart.dataSetsHaveTitle &&
21510
+ dataSetsValues[0] &&
21511
+ labels.length > dataSetsValues[0].data.length) {
21512
+ labels.shift();
21513
+ }
21514
+ ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
21515
+ if (chart.aggregated) {
21516
+ ({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
21517
+ }
21518
+ if (chart.showSubTotals) {
21519
+ labels.push(_t("Subtotal"));
21520
+ }
21521
+ const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
21522
+ const locale = getters.getLocale();
21523
+ const dataSeriesLabels = dataSetsValues.map((dataSet) => dataSet.label);
21524
+ const config = getWaterfallConfiguration(chart, labels, dataSeriesLabels, {
21525
+ format: dataSetFormat,
21526
+ locale,
21527
+ });
21528
+ config.type = "bar";
21529
+ const negativeColor = chart.negativeValuesColor || CHART_WATERFALL_NEGATIVE_COLOR;
21530
+ const positiveColor = chart.positiveValuesColor || CHART_WATERFALL_POSITIVE_COLOR;
21531
+ const subTotalColor = chart.subTotalValuesColor || CHART_WATERFALL_SUBTOTAL_COLOR;
21532
+ const backgroundColor = [];
21533
+ const datasetValues = [];
21534
+ const dataset = {
21535
+ label: "",
21536
+ data: datasetValues,
21537
+ backgroundColor,
21538
+ };
21539
+ const labelsWithSubTotals = [];
21540
+ let lastValue = 0;
21541
+ for (const dataSetsValue of dataSetsValues) {
21542
+ for (let i = 0; i < dataSetsValue.data.length; i++) {
21543
+ const data = dataSetsValue.data[i];
21544
+ labelsWithSubTotals.push(labels[i]);
21545
+ if (isNaN(Number(data))) {
21546
+ datasetValues.push([lastValue, lastValue]);
21547
+ backgroundColor.push("");
21548
+ continue;
21549
+ }
21550
+ datasetValues.push([lastValue, data + lastValue]);
21551
+ let color = data >= 0 ? positiveColor : negativeColor;
21552
+ if (i === 0 && dataSetsValue === dataSetsValues[0] && chart.firstValueAsSubtotal) {
21553
+ color = subTotalColor;
21554
+ }
21555
+ backgroundColor.push(color);
21556
+ lastValue += data;
21557
+ }
21558
+ if (chart.showSubTotals) {
21559
+ labelsWithSubTotals.push(_t("Subtotal"));
21560
+ datasetValues.push([0, lastValue]);
21561
+ backgroundColor.push(subTotalColor);
21562
+ }
21563
+ }
21564
+ config.data.datasets.push(dataset);
21565
+ config.data.labels = labelsWithSubTotals.map(truncateLabel);
21566
+ return { chartJsConfig: config, background: chart.background || BACKGROUND_CHART_COLOR };
21567
+ }
21568
+
21240
21569
  /**
21241
21570
  * This registry is intended to map a cell content (raw string) to
21242
21571
  * an instance of a cell.
@@ -21246,9 +21575,9 @@ stores.inject(MyMetaStore, storeInstance);
21246
21575
  match: (type) => type === "bar",
21247
21576
  createChart: (definition, sheetId, getters) => new BarChart(definition, sheetId, getters),
21248
21577
  getChartRuntime: createBarChartRuntime,
21249
- validateChartDefinition: (validator, definition) => BarChart.validateChartDefinition(validator, definition),
21250
- transformDefinition: (definition, executed) => BarChart.transformDefinition(definition, executed),
21251
- getChartDefinitionFromContextCreation: (context) => BarChart.getDefinitionFromContextCreation(context),
21578
+ validateChartDefinition: BarChart.validateChartDefinition,
21579
+ transformDefinition: BarChart.transformDefinition,
21580
+ getChartDefinitionFromContextCreation: BarChart.getDefinitionFromContextCreation,
21252
21581
  name: _t("Bar"),
21253
21582
  sequence: 10,
21254
21583
  });
@@ -21256,9 +21585,9 @@ stores.inject(MyMetaStore, storeInstance);
21256
21585
  match: (type) => type === "combo",
21257
21586
  createChart: (definition, sheetId, getters) => new ComboChart(definition, sheetId, getters),
21258
21587
  getChartRuntime: createComboChartRuntime,
21259
- validateChartDefinition: (validator, definition) => ComboChart.validateChartDefinition(validator, definition),
21260
- transformDefinition: (definition, executed) => ComboChart.transformDefinition(definition, executed),
21261
- getChartDefinitionFromContextCreation: (context) => ComboChart.getDefinitionFromContextCreation(context),
21588
+ validateChartDefinition: ComboChart.validateChartDefinition,
21589
+ transformDefinition: ComboChart.transformDefinition,
21590
+ getChartDefinitionFromContextCreation: ComboChart.getDefinitionFromContextCreation,
21262
21591
  name: _t("Combo"),
21263
21592
  sequence: 15,
21264
21593
  });
@@ -21266,9 +21595,9 @@ stores.inject(MyMetaStore, storeInstance);
21266
21595
  match: (type) => type === "line",
21267
21596
  createChart: (definition, sheetId, getters) => new LineChart(definition, sheetId, getters),
21268
21597
  getChartRuntime: createLineChartRuntime,
21269
- validateChartDefinition: (validator, definition) => LineChart.validateChartDefinition(validator, definition),
21270
- transformDefinition: (definition, executed) => LineChart.transformDefinition(definition, executed),
21271
- getChartDefinitionFromContextCreation: (context) => LineChart.getDefinitionFromContextCreation(context),
21598
+ validateChartDefinition: LineChart.validateChartDefinition,
21599
+ transformDefinition: LineChart.transformDefinition,
21600
+ getChartDefinitionFromContextCreation: LineChart.getDefinitionFromContextCreation,
21272
21601
  name: _t("Line"),
21273
21602
  sequence: 20,
21274
21603
  });
@@ -21276,9 +21605,9 @@ stores.inject(MyMetaStore, storeInstance);
21276
21605
  match: (type) => type === "pie",
21277
21606
  createChart: (definition, sheetId, getters) => new PieChart(definition, sheetId, getters),
21278
21607
  getChartRuntime: createPieChartRuntime,
21279
- validateChartDefinition: (validator, definition) => PieChart.validateChartDefinition(validator, definition),
21280
- transformDefinition: (definition, executed) => PieChart.transformDefinition(definition, executed),
21281
- getChartDefinitionFromContextCreation: (context) => PieChart.getDefinitionFromContextCreation(context),
21608
+ validateChartDefinition: PieChart.validateChartDefinition,
21609
+ transformDefinition: PieChart.transformDefinition,
21610
+ getChartDefinitionFromContextCreation: PieChart.getDefinitionFromContextCreation,
21282
21611
  name: _t("Pie"),
21283
21612
  sequence: 30,
21284
21613
  });
@@ -21286,9 +21615,9 @@ stores.inject(MyMetaStore, storeInstance);
21286
21615
  match: (type) => type === "scorecard",
21287
21616
  createChart: (definition, sheetId, getters) => new ScorecardChart$1(definition, sheetId, getters),
21288
21617
  getChartRuntime: createScorecardChartRuntime,
21289
- validateChartDefinition: (validator, definition) => ScorecardChart$1.validateChartDefinition(validator, definition),
21290
- transformDefinition: (definition, executed) => ScorecardChart$1.transformDefinition(definition, executed),
21291
- getChartDefinitionFromContextCreation: (context) => ScorecardChart$1.getDefinitionFromContextCreation(context),
21618
+ validateChartDefinition: ScorecardChart$1.validateChartDefinition,
21619
+ transformDefinition: ScorecardChart$1.transformDefinition,
21620
+ getChartDefinitionFromContextCreation: ScorecardChart$1.getDefinitionFromContextCreation,
21292
21621
  name: _t("Scorecard"),
21293
21622
  sequence: 40,
21294
21623
  });
@@ -21296,9 +21625,9 @@ stores.inject(MyMetaStore, storeInstance);
21296
21625
  match: (type) => type === "gauge",
21297
21626
  createChart: (definition, sheetId, getters) => new GaugeChart(definition, sheetId, getters),
21298
21627
  getChartRuntime: createGaugeChartRuntime,
21299
- validateChartDefinition: (validator, definition) => GaugeChart.validateChartDefinition(validator, definition),
21300
- transformDefinition: (definition, executed) => GaugeChart.transformDefinition(definition, executed),
21301
- getChartDefinitionFromContextCreation: (context) => GaugeChart.getDefinitionFromContextCreation(context),
21628
+ validateChartDefinition: GaugeChart.validateChartDefinition,
21629
+ transformDefinition: GaugeChart.transformDefinition,
21630
+ getChartDefinitionFromContextCreation: GaugeChart.getDefinitionFromContextCreation,
21302
21631
  name: _t("Gauge"),
21303
21632
  sequence: 50,
21304
21633
  });
@@ -21306,12 +21635,22 @@ stores.inject(MyMetaStore, storeInstance);
21306
21635
  match: (type) => type === "scatter",
21307
21636
  createChart: (definition, sheetId, getters) => new ScatterChart(definition, sheetId, getters),
21308
21637
  getChartRuntime: createScatterChartRuntime,
21309
- validateChartDefinition: (validator, definition) => ScatterChart.validateChartDefinition(validator, definition),
21310
- transformDefinition: (definition, executed) => ScatterChart.transformDefinition(definition, executed),
21311
- getChartDefinitionFromContextCreation: (context) => ScatterChart.getDefinitionFromContextCreation(context),
21638
+ validateChartDefinition: ScatterChart.validateChartDefinition,
21639
+ transformDefinition: ScatterChart.transformDefinition,
21640
+ getChartDefinitionFromContextCreation: ScatterChart.getDefinitionFromContextCreation,
21312
21641
  name: _t("Scatter"),
21313
21642
  sequence: 60,
21314
21643
  });
21644
+ chartRegistry.add("waterfall", {
21645
+ match: (type) => type === "waterfall",
21646
+ createChart: (definition, sheetId, getters) => new WaterfallChart(definition, sheetId, getters),
21647
+ getChartRuntime: createWaterfallChartRuntime,
21648
+ validateChartDefinition: WaterfallChart.validateChartDefinition,
21649
+ transformDefinition: WaterfallChart.transformDefinition,
21650
+ getChartDefinitionFromContextCreation: WaterfallChart.getDefinitionFromContextCreation,
21651
+ name: _t("Waterfall"),
21652
+ sequence: 70,
21653
+ });
21315
21654
  const chartComponentRegistry = new Registry();
21316
21655
  chartComponentRegistry.add("line", ChartJsComponent);
21317
21656
  chartComponentRegistry.add("bar", ChartJsComponent);
@@ -21320,6 +21659,7 @@ stores.inject(MyMetaStore, storeInstance);
21320
21659
  chartComponentRegistry.add("gauge", GaugeChartComponent);
21321
21660
  chartComponentRegistry.add("scatter", ChartJsComponent);
21322
21661
  chartComponentRegistry.add("scorecard", ScorecardChart);
21662
+ chartComponentRegistry.add("waterfall", ChartJsComponent);
21323
21663
 
21324
21664
  /**
21325
21665
  * Registry intended to support usual currencies. It is mainly used to create
@@ -23299,6 +23639,7 @@ stores.inject(MyMetaStore, storeInstance);
23299
23639
  this.save();
23300
23640
  }
23301
23641
  ev.stopPropagation();
23642
+ ev.preventDefault();
23302
23643
  break;
23303
23644
  case "Escape":
23304
23645
  this.cancel();
@@ -26952,8 +27293,8 @@ stores.inject(MyMetaStore, storeInstance);
26952
27293
  };
26953
27294
  }
26954
27295
 
26955
- class LineBarPieConfigPanel extends owl.Component {
26956
- static template = "o-spreadsheet-LineBarPieConfigPanel";
27296
+ class GenericChartConfigPanel extends owl.Component {
27297
+ static template = "o-spreadsheet-GenericChartConfigPanel";
26957
27298
  static components = {
26958
27299
  SelectionInput,
26959
27300
  ValidationMessages,
@@ -27070,7 +27411,7 @@ stores.inject(MyMetaStore, storeInstance);
27070
27411
  }
27071
27412
  }
27072
27413
 
27073
- class BarConfigPanel extends LineBarPieConfigPanel {
27414
+ class BarConfigPanel extends GenericChartConfigPanel {
27074
27415
  static template = "o-spreadsheet-BarConfigPanel";
27075
27416
  get stackedLabel() {
27076
27417
  return _t("Stacked barchart");
@@ -27677,8 +28018,8 @@ stores.inject(MyMetaStore, storeInstance);
27677
28018
  }
27678
28019
  }
27679
28020
 
27680
- class LineBarPieDesignPanel extends owl.Component {
27681
- static template = "o-spreadsheet-LineBarPieDesignPanel";
28021
+ class GenericChartDesignPanel extends owl.Component {
28022
+ static template = "o-spreadsheet-GenericChartDesignPanel";
27682
28023
  static components = { RoundColorPicker, ChartTitle, Section };
27683
28024
  static props = {
27684
28025
  figureId: String,
@@ -27707,11 +28048,11 @@ stores.inject(MyMetaStore, storeInstance);
27707
28048
  }
27708
28049
  }
27709
28050
 
27710
- class BarChartDesignPanel extends LineBarPieDesignPanel {
28051
+ class BarChartDesignPanel extends GenericChartDesignPanel {
27711
28052
  static template = "o-spreadsheet-BarChartDesignPanel";
27712
28053
  }
27713
28054
 
27714
- class ComboChartConfigPanel extends LineBarPieConfigPanel {
28055
+ class ComboChartConfigPanel extends GenericChartConfigPanel {
27715
28056
  static template = "o-spreadsheet-ComboChartConfigPanel";
27716
28057
  get shouldUseRightAxis() {
27717
28058
  return _t("Use right axis for line series");
@@ -27723,7 +28064,7 @@ stores.inject(MyMetaStore, storeInstance);
27723
28064
  }
27724
28065
  }
27725
28066
 
27726
- class ComboChartDesignPanel extends LineBarPieDesignPanel {
28067
+ class ComboChartDesignPanel extends GenericChartDesignPanel {
27727
28068
  static template = "o-spreadsheet-ComboChartDesignPanel";
27728
28069
  }
27729
28070
 
@@ -27876,7 +28217,7 @@ stores.inject(MyMetaStore, storeInstance);
27876
28217
  }
27877
28218
  }
27878
28219
 
27879
- class LineConfigPanel extends LineBarPieConfigPanel {
28220
+ class LineConfigPanel extends GenericChartConfigPanel {
27880
28221
  static template = "o-spreadsheet-LineConfigPanel";
27881
28222
  get canTreatLabelsAsText() {
27882
28223
  const chart = this.env.model.getters.getChart(this.props.figureId);
@@ -27925,11 +28266,11 @@ stores.inject(MyMetaStore, storeInstance);
27925
28266
  }
27926
28267
  }
27927
28268
 
27928
- class LineChartDesignPanel extends LineBarPieDesignPanel {
28269
+ class LineChartDesignPanel extends GenericChartDesignPanel {
27929
28270
  static template = "o-spreadsheet-LineChartDesignPanel";
27930
28271
  }
27931
28272
 
27932
- class ScatterConfigPanel extends LineBarPieConfigPanel {
28273
+ class ScatterConfigPanel extends GenericChartConfigPanel {
27933
28274
  static template = "o-spreadsheet-ScatterConfigPanel";
27934
28275
  get canTreatLabelsAsText() {
27935
28276
  const chart = this.env.model.getters.getChart(this.props.figureId);
@@ -28068,6 +28409,46 @@ stores.inject(MyMetaStore, storeInstance);
28068
28409
  }
28069
28410
  }
28070
28411
 
28412
+ class WaterfallChartDesignPanel extends GenericChartDesignPanel {
28413
+ static template = "o-spreadsheet-WaterfallChartDesignPanel";
28414
+ static components = { ...GenericChartDesignPanel.components, Checkbox, RoundColorPicker };
28415
+ state = owl.useState({ pickerOpened: false });
28416
+ setup() {
28417
+ super.setup();
28418
+ owl.useExternalListener(window, "click", this.closePicker);
28419
+ }
28420
+ onUpdateShowSubTotals(showSubTotals) {
28421
+ this.props.updateChart(this.props.figureId, { showSubTotals });
28422
+ }
28423
+ onUpdateShowConnectorLines(showConnectorLines) {
28424
+ this.props.updateChart(this.props.figureId, { showConnectorLines });
28425
+ }
28426
+ onUpdateFirstValueAsSubtotal(firstValueAsSubtotal) {
28427
+ this.props.updateChart(this.props.figureId, { firstValueAsSubtotal });
28428
+ }
28429
+ updateColor(colorName, color) {
28430
+ this.props.updateChart(this.props.figureId, { [colorName]: color });
28431
+ }
28432
+ closePicker() {
28433
+ this.state.pickerOpened = false;
28434
+ }
28435
+ togglePicker() {
28436
+ this.state.pickerOpened = !this.state.pickerOpened;
28437
+ }
28438
+ get positiveValuesColor() {
28439
+ return (this.props.definition.positiveValuesColor ||
28440
+ CHART_WATERFALL_POSITIVE_COLOR);
28441
+ }
28442
+ get negativeValuesColor() {
28443
+ return (this.props.definition.negativeValuesColor ||
28444
+ CHART_WATERFALL_NEGATIVE_COLOR);
28445
+ }
28446
+ get subTotalValuesColor() {
28447
+ return (this.props.definition.subTotalValuesColor ||
28448
+ CHART_WATERFALL_SUBTOTAL_COLOR);
28449
+ }
28450
+ }
28451
+
28071
28452
  const chartSidePanelComponentRegistry = new Registry();
28072
28453
  chartSidePanelComponentRegistry
28073
28454
  .add("line", {
@@ -28087,8 +28468,8 @@ stores.inject(MyMetaStore, storeInstance);
28087
28468
  design: ComboChartDesignPanel,
28088
28469
  })
28089
28470
  .add("pie", {
28090
- configuration: LineBarPieConfigPanel,
28091
- design: LineBarPieDesignPanel,
28471
+ configuration: GenericChartConfigPanel,
28472
+ design: GenericChartDesignPanel,
28092
28473
  })
28093
28474
  .add("gauge", {
28094
28475
  configuration: GaugeChartConfigPanel,
@@ -28097,6 +28478,10 @@ stores.inject(MyMetaStore, storeInstance);
28097
28478
  .add("scorecard", {
28098
28479
  configuration: ScorecardChartConfigPanel,
28099
28480
  design: ScorecardChartDesignPanel,
28481
+ })
28482
+ .add("waterfall", {
28483
+ configuration: GenericChartConfigPanel,
28484
+ design: WaterfallChartDesignPanel,
28100
28485
  });
28101
28486
 
28102
28487
  class MainChartPanelStore extends SpreadsheetStore {
@@ -30834,6 +31219,9 @@ stores.inject(MyMetaStore, storeInstance);
30834
31219
  filteredRange: filteredZone.top > filteredZone.bottom ? undefined : filteredRange,
30835
31220
  };
30836
31221
  }
31222
+ function isStaticTable(table) {
31223
+ return table.type === "static" || table.type === "forceStatic";
31224
+ }
30837
31225
  function getComputedTableStyle(tableConfig, numberOfCols, numberOfRows) {
30838
31226
  return {
30839
31227
  borders: getAllTableBorders(tableConfig, numberOfCols, numberOfRows),
@@ -31368,7 +31756,12 @@ stores.inject(MyMetaStore, storeInstance);
31368
31756
  const extendedZone = this.env.model.getters.getContiguousZone(sheetId, newRange.zone);
31369
31757
  newRange = this.env.model.getters.getRangeFromZone(sheetId, extendedZone);
31370
31758
  }
31371
- const result = this.env.model.dispatch("UPDATE_TABLE", {
31759
+ const newTableZone = newRange.zone;
31760
+ const oldTableZone = this.props.table.range.zone;
31761
+ const cmdToCall = newTableZone.top === oldTableZone.top && newTableZone.left === oldTableZone.left
31762
+ ? "RESIZE_TABLE"
31763
+ : "UPDATE_TABLE";
31764
+ const result = this.env.model.dispatch(cmdToCall, {
31372
31765
  sheetId,
31373
31766
  zone: this.props.table.range.zone,
31374
31767
  newTableRange: newRange.rangeData,
@@ -31857,6 +32250,38 @@ stores.inject(MyMetaStore, storeInstance);
31857
32250
  }
31858
32251
  }
31859
32252
 
32253
+ class ArrayFormulaHighlight extends SpreadsheetStore {
32254
+ highlightStore = this.get(HighlightStore);
32255
+ constructor(get) {
32256
+ super(get);
32257
+ this.highlightStore.register(this);
32258
+ }
32259
+ get highlights() {
32260
+ const zone = this.getHighlightZone();
32261
+ if (!zone) {
32262
+ return [];
32263
+ }
32264
+ const sheetId = this.model.getters.getActiveSheetId();
32265
+ return [
32266
+ {
32267
+ sheetId,
32268
+ zone,
32269
+ color: "#17A2B8",
32270
+ noFill: true,
32271
+ thinLine: true,
32272
+ },
32273
+ ];
32274
+ }
32275
+ getHighlightZone() {
32276
+ const position = this.model.getters.getActivePosition();
32277
+ const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
32278
+ const spreadZone = spreader
32279
+ ? this.model.getters.getSpreadZone(spreader)
32280
+ : this.model.getters.getSpreadZone(position);
32281
+ return spreadZone;
32282
+ }
32283
+ }
32284
+
31860
32285
  // -----------------------------------------------------------------------------
31861
32286
  // Autofill
31862
32287
  // -----------------------------------------------------------------------------
@@ -33633,6 +34058,10 @@ stores.inject(MyMetaStore, storeInstance);
33633
34058
  height: 0px;
33634
34059
  }
33635
34060
  }
34061
+ .o-figure-container {
34062
+ -webkit-user-select: none; // safari
34063
+ user-select: none;
34064
+ }
33636
34065
  `;
33637
34066
  /**
33638
34067
  * Each figure ⭐ is positioned inside a container `div` placed and sized
@@ -36034,6 +36463,77 @@ stores.inject(MyMetaStore, storeInstance);
36034
36463
  }
36035
36464
  }
36036
36465
 
36466
+ const SIZE = 3;
36467
+ const COLOR = "#777";
36468
+ css /* scss */ `
36469
+ .o-table-resizer {
36470
+ width: ${SIZE}px;
36471
+ height: ${SIZE}px;
36472
+ border-bottom: ${SIZE}px solid ${COLOR};
36473
+ border-right: ${SIZE}px solid ${COLOR};
36474
+ cursor: nwse-resize;
36475
+ }
36476
+ `;
36477
+ class TableResizer extends owl.Component {
36478
+ static template = "o-spreadsheet-TableResizer";
36479
+ static props = { table: Object };
36480
+ state = owl.useState({ highlightZone: undefined });
36481
+ setup() {
36482
+ useHighlights(this);
36483
+ }
36484
+ get containerStyle() {
36485
+ const tableZone = this.props.table.range.zone;
36486
+ const bottomRight = { ...tableZone, left: tableZone.right, top: tableZone.bottom };
36487
+ const rect = this.env.model.getters.getVisibleRect(bottomRight);
36488
+ if (rect.height === 0 || rect.width === 0) {
36489
+ return cssPropertiesToCss({ display: "none" });
36490
+ }
36491
+ return cssPropertiesToCss({
36492
+ top: `${rect.y + rect.height - SIZE * 2}px`,
36493
+ left: `${rect.x + rect.width - SIZE * 2}px`,
36494
+ });
36495
+ }
36496
+ onMouseDown(ev) {
36497
+ const tableZone = this.props.table.range.zone;
36498
+ const topLeft = { col: tableZone.left, row: tableZone.top };
36499
+ document.body.style.cursor = "nwse-resize";
36500
+ const onMouseUp = () => {
36501
+ document.body.style.cursor = "";
36502
+ const newTableZone = this.state.highlightZone;
36503
+ if (!newTableZone)
36504
+ return;
36505
+ const sheetId = this.props.table.range.sheetId;
36506
+ this.env.model.dispatch("RESIZE_TABLE", {
36507
+ sheetId,
36508
+ zone: this.props.table.range.zone,
36509
+ newTableRange: this.env.model.getters.getRangeDataFromZone(sheetId, newTableZone),
36510
+ });
36511
+ this.state.highlightZone = undefined;
36512
+ };
36513
+ const onMouseMove = (col, row, ev) => {
36514
+ this.state.highlightZone = {
36515
+ left: topLeft.col,
36516
+ top: topLeft.row,
36517
+ right: Math.max(col, topLeft.col),
36518
+ bottom: Math.max(row, topLeft.row),
36519
+ };
36520
+ };
36521
+ dragAndDropBeyondTheViewport(this.env, onMouseMove, onMouseUp);
36522
+ }
36523
+ get highlights() {
36524
+ if (!this.state.highlightZone)
36525
+ return [];
36526
+ return [
36527
+ {
36528
+ zone: this.state.highlightZone,
36529
+ sheetId: this.props.table.range.sheetId,
36530
+ color: COLOR,
36531
+ noFill: true,
36532
+ },
36533
+ ];
36534
+ }
36535
+ }
36536
+
36037
36537
  const registries$1 = {
36038
36538
  ROW: rowMenuRegistry,
36039
36539
  COL: colMenuRegistry,
@@ -36061,6 +36561,7 @@ stores.inject(MyMetaStore, storeInstance);
36061
36561
  Popover,
36062
36562
  VerticalScrollBar,
36063
36563
  HorizontalScrollBar,
36564
+ TableResizer,
36064
36565
  };
36065
36566
  HEADER_HEIGHT = HEADER_HEIGHT;
36066
36567
  HEADER_WIDTH = HEADER_WIDTH;
@@ -36089,6 +36590,7 @@ stores.inject(MyMetaStore, storeInstance);
36089
36590
  this.composerFocusStore = useStore(ComposerFocusStore);
36090
36591
  this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
36091
36592
  this.sidePanel = useStore(SidePanelStore);
36593
+ useStore(ArrayFormulaHighlight);
36092
36594
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
36093
36595
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
36094
36596
  owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
@@ -36657,6 +37159,10 @@ stores.inject(MyMetaStore, storeInstance);
36657
37159
  onComposerContentFocused() {
36658
37160
  this.composerFocusStore.focusGridComposerContent();
36659
37161
  }
37162
+ get staticTables() {
37163
+ const sheetId = this.env.model.getters.getActiveSheetId();
37164
+ return this.env.model.getters.getCoreTables(sheetId).filter(isStaticTable);
37165
+ }
36660
37166
  }
36661
37167
 
36662
37168
  /**
@@ -45450,7 +45956,7 @@ stores.inject(MyMetaStore, storeInstance);
45450
45956
  }
45451
45957
 
45452
45958
  class TablePlugin extends CorePlugin {
45453
- static getters = ["getCoreTable", "getCoreTables"];
45959
+ static getters = ["getCoreTable", "getCoreTables", "getCoreTableMatchingTopLeft"];
45454
45960
  tables = {};
45455
45961
  adaptRanges(applyChange, sheetId) {
45456
45962
  const sheetIds = sheetId ? [sheetId] : this.getters.getSheetIds();
@@ -45471,7 +45977,7 @@ stores.inject(MyMetaStore, storeInstance);
45471
45977
  ? "TableOverlap" /* CommandResult.TableOverlap */
45472
45978
  : "Success" /* CommandResult.Success */, (cmd) => this.checkTableConfigUpdateIsValid(cmd.config));
45473
45979
  case "UPDATE_TABLE":
45474
- const updatedTable = this.getTableFromZone(cmd.sheetId, cmd.zone);
45980
+ const updatedTable = this.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
45475
45981
  if (!updatedTable) {
45476
45982
  return "TableNotFound" /* CommandResult.TableNotFound */;
45477
45983
  }
@@ -45627,10 +46133,9 @@ stores.inject(MyMetaStore, storeInstance);
45627
46133
  }
45628
46134
  return direction;
45629
46135
  }
45630
- getTableFromZone(sheetId, zone) {
46136
+ getCoreTableMatchingTopLeft(sheetId, zone) {
45631
46137
  for (const table of this.getCoreTables(sheetId)) {
45632
46138
  const tableZone = table.range.zone;
45633
- // Only check top left to match dynamic tables
45634
46139
  if (tableZone.left === zone.left && tableZone.top === zone.top) {
45635
46140
  return table;
45636
46141
  }
@@ -45646,7 +46151,7 @@ stores.inject(MyMetaStore, storeInstance);
45646
46151
  if (zoneIsInSheet !== "Success" /* CommandResult.Success */) {
45647
46152
  return zoneIsInSheet;
45648
46153
  }
45649
- const updatedTable = this.getTableFromZone(cmd.sheetId, cmd.zone);
46154
+ const updatedTable = this.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
45650
46155
  if (!updatedTable) {
45651
46156
  return "TableNotFound" /* CommandResult.TableNotFound */;
45652
46157
  }
@@ -45696,7 +46201,7 @@ stores.inject(MyMetaStore, storeInstance);
45696
46201
  };
45697
46202
  }
45698
46203
  updateTable(cmd) {
45699
- const table = this.getTableFromZone(cmd.sheetId, cmd.zone);
46204
+ const table = this.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
45700
46205
  if (!table) {
45701
46206
  return;
45702
46207
  }
@@ -51737,6 +52242,7 @@ stores.inject(MyMetaStore, storeInstance);
51737
52242
  "UPDATE_TABLE",
51738
52243
  "UPDATE_FILTER",
51739
52244
  "REMOVE_TABLE",
52245
+ "RESIZE_TABLE",
51740
52246
  ];
51741
52247
  const invalidateTableStyleCommandsSet = new Set(invalidateTableStyleCommands);
51742
52248
  function doesCommandInvalidatesTableStyle(cmd) {
@@ -52371,7 +52877,10 @@ stores.inject(MyMetaStore, storeInstance);
52371
52877
  const { col, row } = cmd;
52372
52878
  const tableContentZone = getTableContentZone(table.range.zone, table.config);
52373
52879
  if (tableContentZone && isInside(col, row, tableContentZone)) {
52374
- this.autofillTableZone(cmd, tableContentZone);
52880
+ const top = cmd.autofillRowStart ?? tableContentZone.top;
52881
+ const bottom = cmd.autofillRowEnd ?? tableContentZone.bottom;
52882
+ const autofillZone = { ...tableContentZone, top, bottom };
52883
+ this.autofillTableZone(cmd, autofillZone);
52375
52884
  }
52376
52885
  break;
52377
52886
  }
@@ -52405,6 +52914,50 @@ stores.inject(MyMetaStore, storeInstance);
52405
52914
  }
52406
52915
  }
52407
52916
 
52917
+ class TableResizeUI extends UIPlugin {
52918
+ allowDispatch(cmd) {
52919
+ switch (cmd.type) {
52920
+ case "RESIZE_TABLE":
52921
+ const table = this.getters.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
52922
+ if (!table) {
52923
+ return "TableNotFound" /* CommandResult.TableNotFound */;
52924
+ }
52925
+ const oldTableZone = table.range.zone;
52926
+ const newTableZone = this.getters.getRangeFromRangeData(cmd.newTableRange).zone;
52927
+ if (newTableZone.top !== oldTableZone.top || newTableZone.left !== oldTableZone.left) {
52928
+ return "InvalidTableResize" /* CommandResult.InvalidTableResize */;
52929
+ }
52930
+ return this.canDispatch("UPDATE_TABLE", { ...cmd }).reasons;
52931
+ }
52932
+ return "Success" /* CommandResult.Success */;
52933
+ }
52934
+ handle(cmd) {
52935
+ switch (cmd.type) {
52936
+ case "RESIZE_TABLE": {
52937
+ const table = this.getters.getCoreTableMatchingTopLeft(cmd.sheetId, cmd.zone);
52938
+ this.dispatch("UPDATE_TABLE", { ...cmd });
52939
+ if (!table || !table.config.automaticAutofill)
52940
+ return;
52941
+ const oldTableZone = table.range.zone;
52942
+ const newTableZone = this.getters.getRangeFromRangeData(cmd.newTableRange).zone;
52943
+ if (newTableZone.bottom >= oldTableZone.bottom) {
52944
+ for (let col = newTableZone.left; col <= newTableZone.right; col++) {
52945
+ const autofillSource = { col, row: oldTableZone.bottom, sheetId: cmd.sheetId };
52946
+ if (this.getters.getCell(autofillSource)?.content.startsWith("=")) {
52947
+ this.dispatch("AUTOFILL_TABLE_COLUMN", {
52948
+ ...autofillSource,
52949
+ autofillRowStart: oldTableZone.bottom,
52950
+ autofillRowEnd: newTableZone.bottom,
52951
+ });
52952
+ }
52953
+ }
52954
+ break;
52955
+ }
52956
+ }
52957
+ }
52958
+ }
52959
+ }
52960
+
52408
52961
  /**
52409
52962
  * Clipboard Plugin
52410
52963
  *
@@ -54079,13 +54632,14 @@ stores.inject(MyMetaStore, storeInstance);
54079
54632
  }
54080
54633
  }
54081
54634
  handleEvent(event) {
54635
+ const sheetId = this.getters.getActiveSheetId();
54082
54636
  if (event.options.scrollIntoView) {
54083
54637
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
54084
54638
  if (event.mode === "updateAnchor") {
54085
54639
  const oldZone = event.previousAnchor.zone;
54086
54640
  const newZone = event.anchor.zone;
54087
54641
  // altering a zone should not move the viewport in a dimension that wasn't changed
54088
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
54642
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
54089
54643
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
54090
54644
  col = left > col || col > right ? left : col;
54091
54645
  }
@@ -54093,7 +54647,6 @@ stores.inject(MyMetaStore, storeInstance);
54093
54647
  row = top > row || row > bottom ? top : row;
54094
54648
  }
54095
54649
  }
54096
- const sheetId = this.getters.getActiveSheetId();
54097
54650
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
54098
54651
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
54099
54652
  if (!this.sheetsWithDirtyViewports.has(sheetId)) {
@@ -54130,16 +54683,16 @@ stores.inject(MyMetaStore, storeInstance);
54130
54683
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
54131
54684
  break;
54132
54685
  case "SHIFT_VIEWPORT_DOWN":
54133
- const { top } = this.getActiveMainViewport();
54134
54686
  const sheetId = this.getters.getActiveSheetId();
54135
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
54136
- this.shiftVertically(shiftedOffsetY);
54687
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
54688
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
54689
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
54137
54690
  break;
54138
54691
  case "SHIFT_VIEWPORT_UP": {
54139
- const { top } = this.getActiveMainViewport();
54140
54692
  const sheetId = this.getters.getActiveSheetId();
54141
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
54142
- this.shiftVertically(shiftedOffsetY);
54693
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
54694
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
54695
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
54143
54696
  break;
54144
54697
  }
54145
54698
  case "REMOVE_TABLE":
@@ -54562,17 +55115,6 @@ stores.inject(MyMetaStore, storeInstance);
54562
55115
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
54563
55116
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
54564
55117
  }
54565
- /**
54566
- * Clip the vertical offset within the allowed range.
54567
- * Not above the sheet, nor below the sheet.
54568
- */
54569
- clipOffsetY(offsetY) {
54570
- const { height } = this.getMainViewportRect();
54571
- const maxOffset = height - this.sheetViewHeight;
54572
- offsetY = Math.min(offsetY, maxOffset);
54573
- offsetY = Math.max(offsetY, 0);
54574
- return offsetY;
54575
- }
54576
55118
  getViewportOffset(sheetId) {
54577
55119
  return {
54578
55120
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -54628,12 +55170,15 @@ stores.inject(MyMetaStore, storeInstance);
54628
55170
  * viewport top.
54629
55171
  */
54630
55172
  shiftVertically(offset) {
54631
- const { top } = this.getActiveMainViewport();
55173
+ const sheetId = this.getters.getActiveSheetId();
55174
+ const { top } = this.getMainInternalViewport(sheetId);
54632
55175
  const { scrollX } = this.getActiveSheetScrollInfo();
54633
55176
  this.setSheetViewOffset(scrollX, offset);
54634
55177
  const { anchor } = this.getters.getSelection();
54635
- const deltaRow = this.getActiveMainViewport().top - top;
54636
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
55178
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
55179
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
55180
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
55181
+ }
54637
55182
  }
54638
55183
  getVisibleFigures() {
54639
55184
  const sheetId = this.getters.getActiveSheetId();
@@ -54822,7 +55367,8 @@ stores.inject(MyMetaStore, storeInstance);
54822
55367
  .add("collaborative", CollaborativePlugin)
54823
55368
  .add("history", HistoryPlugin)
54824
55369
  .add("data_cleanup", DataCleanupPlugin)
54825
- .add("table_autofill", TableAutofillPlugin);
55370
+ .add("table_autofill", TableAutofillPlugin)
55371
+ .add("table_ui_resize", TableResizeUI);
54826
55372
  // Plugins which have a state, but which should not be shared in collaborative
54827
55373
  const statefulUIPluginRegistry = new Registry()
54828
55374
  .add("selection", GridSelectionPlugin)
@@ -54890,38 +55436,6 @@ stores.inject(MyMetaStore, storeInstance);
54890
55436
  }
54891
55437
  }
54892
55438
 
54893
- class ArrayFormulaHighlight extends SpreadsheetStore {
54894
- highlightStore = this.get(HighlightStore);
54895
- constructor(get) {
54896
- super(get);
54897
- this.highlightStore.register(this);
54898
- }
54899
- get highlights() {
54900
- const zone = this.getHighlightZone();
54901
- if (!zone) {
54902
- return [];
54903
- }
54904
- const sheetId = this.model.getters.getActiveSheetId();
54905
- return [
54906
- {
54907
- sheetId,
54908
- zone,
54909
- color: "#17A2B8",
54910
- noFill: true,
54911
- thinLine: true,
54912
- },
54913
- ];
54914
- }
54915
- getHighlightZone() {
54916
- const position = this.model.getters.getActivePosition();
54917
- const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
54918
- const spreadZone = spreader
54919
- ? this.model.getters.getSpreadZone(spreader)
54920
- : this.model.getters.getSpreadZone(position);
54921
- return spreadZone;
54922
- }
54923
- }
54924
-
54925
55439
  const RIPPLE_KEY_FRAMES = [
54926
55440
  { transform: "scale(0)" },
54927
55441
  { transform: "scale(0.8)", offset: 0.33 },
@@ -57255,7 +57769,6 @@ stores.inject(MyMetaStore, storeInstance);
57255
57769
  this.notificationStore = useStore(NotificationStore);
57256
57770
  this.composerFocusStore = useStore(ComposerFocusStore);
57257
57771
  this.sidePanel = useStore(SidePanelStore);
57258
- useStore(ArrayFormulaHighlight);
57259
57772
  this.keyDownMapping = {
57260
57773
  "CTRL+H": () => this.sidePanel.toggle("FindAndReplace", {}),
57261
57774
  "CTRL+F": () => this.sidePanel.toggle("FindAndReplace", {}),
@@ -61197,9 +61710,9 @@ stores.inject(MyMetaStore, storeInstance);
61197
61710
  GridOverlay,
61198
61711
  ScorecardChart,
61199
61712
  LineConfigPanel,
61200
- LineBarPieDesignPanel,
61713
+ GenericChartDesignPanel,
61201
61714
  BarConfigPanel,
61202
- LineBarPieConfigPanel,
61715
+ GenericChartConfigPanel,
61203
61716
  GaugeChartConfigPanel,
61204
61717
  GaugeChartDesignPanel,
61205
61718
  ScorecardChartConfigPanel,
@@ -61288,9 +61801,9 @@ stores.inject(MyMetaStore, storeInstance);
61288
61801
  exports.tokenize = tokenize;
61289
61802
 
61290
61803
 
61291
- __info__.version = "17.3.0-alpha.3";
61292
- __info__.date = "2024-04-10T12:28:23.658Z";
61293
- __info__.hash = "80b5056";
61804
+ __info__.version = "17.3.0-alpha.4";
61805
+ __info__.date = "2024-04-15T11:02:51.551Z";
61806
+ __info__.hash = "a32a1df";
61294
61807
 
61295
61808
 
61296
61809
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);