@odoo/o-spreadsheet 17.3.0-alpha.6 → 17.3.0-alpha.7

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.6
7
- * @date 2024-04-26T07:39:53.611Z
8
- * @hash f58a0d5
6
+ * @version 17.3.0-alpha.7
7
+ * @date 2024-05-07T10:42:47.288Z
8
+ * @hash 853c266
9
9
  */
10
10
 
11
11
  'use strict';
@@ -568,7 +568,7 @@ function getAddHeaderStartIndex(position, base) {
568
568
  /**
569
569
  * Compares two objects.
570
570
  */
571
- function deepEquals(o1, o2) {
571
+ function deepEquals(o1, o2, ignoreFunctions) {
572
572
  if (o1 === o2)
573
573
  return true;
574
574
  if ((o1 && !o2) || (o2 && !o1))
@@ -584,13 +584,16 @@ function deepEquals(o1, o2) {
584
584
  }
585
585
  }
586
586
  for (const key in o1) {
587
- if (typeof o1[key] !== typeof o2[key])
587
+ const typeOfO1Key = typeof o1[key];
588
+ if (typeOfO1Key !== typeof o2[key])
588
589
  return false;
589
- if (typeof o1[key] === "object") {
590
- if (!deepEquals(o1[key], o2[key]))
590
+ if (typeOfO1Key === "object") {
591
+ if (!deepEquals(o1[key], o2[key], ignoreFunctions))
591
592
  return false;
592
593
  }
593
594
  else {
595
+ if (ignoreFunctions && typeOfO1Key === "function")
596
+ return true;
594
597
  if (o1[key] !== o2[key])
595
598
  return false;
596
599
  }
@@ -2241,6 +2244,7 @@ const CellErrorType = {
2241
2244
  CircularDependency: "#CYCLE",
2242
2245
  UnknownFunction: "#NAME?",
2243
2246
  DivisionByZero: "#DIV/0!",
2247
+ SpilledBlocked: "#SPILL!",
2244
2248
  GenericError: "#ERROR",
2245
2249
  };
2246
2250
  const errorTypes = new Set(Object.values(CellErrorType));
@@ -2276,6 +2280,11 @@ class UnknownFunctionError extends EvaluationError {
2276
2280
  super(message, CellErrorType.UnknownFunction);
2277
2281
  }
2278
2282
  }
2283
+ class SplillBlockedError extends EvaluationError {
2284
+ constructor(message = _t("Spill range is not empty")) {
2285
+ super(message, CellErrorType.SpilledBlocked);
2286
+ }
2287
+ }
2279
2288
 
2280
2289
  // HELPERS
2281
2290
  const SORT_TYPES_ORDER = ["number", "string", "boolean", "undefined"];
@@ -4134,21 +4143,22 @@ function toZoneWithoutBoundaryChanges(xc) {
4134
4143
  xc = xc.split("!").at(-1);
4135
4144
  }
4136
4145
  if (xc.includes("$")) {
4137
- xc = xc.replace(/\$/g, "");
4146
+ xc = xc.replaceAll("$", "");
4138
4147
  }
4139
- let ranges;
4148
+ let firstRangePart = "";
4149
+ let secondRangePart;
4140
4150
  if (xc.includes(":")) {
4141
- ranges = xc.split(":").map((x) => x.trim());
4151
+ [firstRangePart, secondRangePart] = xc.split(":");
4152
+ firstRangePart = firstRangePart.trim();
4153
+ secondRangePart = secondRangePart.trim();
4142
4154
  }
4143
4155
  else {
4144
- ranges = [xc.trim()];
4156
+ firstRangePart = xc.trim();
4145
4157
  }
4146
4158
  let top, bottom, left, right;
4147
4159
  let fullCol = false;
4148
4160
  let fullRow = false;
4149
4161
  let hasHeader = false;
4150
- const firstRangePart = ranges[0];
4151
- const secondRangePart = ranges[1] && ranges[1];
4152
4162
  if (isColReference(firstRangePart)) {
4153
4163
  left = right = lettersToNumber(firstRangePart);
4154
4164
  top = bottom = 0;
@@ -4165,7 +4175,7 @@ function toZoneWithoutBoundaryChanges(xc) {
4165
4175
  top = bottom = c.row;
4166
4176
  hasHeader = true;
4167
4177
  }
4168
- if (ranges.length === 2) {
4178
+ if (secondRangePart) {
4169
4179
  if (isColReference(secondRangePart)) {
4170
4180
  right = lettersToNumber(secondRangePart);
4171
4181
  fullCol = true;
@@ -8658,6 +8668,9 @@ function drawHighlight(renderingContext, highlight, rect) {
8658
8668
  const color = highlight.color || HIGHLIGHT_COLOR;
8659
8669
  const { ctx } = renderingContext;
8660
8670
  if (!highlight.noBorder) {
8671
+ if (highlight.dashed) {
8672
+ ctx.setLineDash([5, 3]);
8673
+ }
8661
8674
  ctx.strokeStyle = color;
8662
8675
  if (highlight.thinLine) {
8663
8676
  ctx.lineWidth = 1;
@@ -9351,8 +9364,7 @@ class ComposerStore extends SpreadsheetStore {
9351
9364
  const exactMatch = proposals?.find((p) => p.text === tokenAtCursor.value);
9352
9365
  // remove tokens that are likely to be other parts of the formula that slipped in the token if it's a string
9353
9366
  const searchTerm = tokenAtCursor.value.replace(/[ ,\(\)]/g, "");
9354
- const initialContent = this.initialContent;
9355
- if (exactMatch && exactMatch.text !== initialContent) {
9367
+ if (exactMatch && this._currentContent !== this.initialContent) {
9356
9368
  // this means the user has chosen a proposal
9357
9369
  return;
9358
9370
  }
@@ -9360,7 +9372,7 @@ class ComposerStore extends SpreadsheetStore {
9360
9372
  proposals &&
9361
9373
  !["ARG_SEPARATOR", "LEFT_PAREN"].includes(tokenAtCursor.type)) {
9362
9374
  const filteredProposals = fuzzyLookup(searchTerm, proposals, (p) => p.fuzzySearchKey || p.text);
9363
- if (!exactMatch) {
9375
+ if (!exactMatch || filteredProposals.length > 1) {
9364
9376
  proposals = filteredProposals;
9365
9377
  }
9366
9378
  }
@@ -9551,6 +9563,7 @@ class ChartJsComponent extends owl.Component {
9551
9563
  };
9552
9564
  canvas = owl.useRef("graphContainer");
9553
9565
  chart;
9566
+ currentRuntime;
9554
9567
  get background() {
9555
9568
  return this.chartRuntime.background;
9556
9569
  }
@@ -9567,9 +9580,18 @@ class ChartJsComponent extends owl.Component {
9567
9580
  setup() {
9568
9581
  owl.onMounted(() => {
9569
9582
  const runtime = this.chartRuntime;
9570
- this.createChart(runtime.chartJsConfig);
9583
+ this.currentRuntime = runtime;
9584
+ // Note: chartJS modify the runtime in place, so it's important to give it a copy
9585
+ this.createChart(deepCopy(runtime.chartJsConfig));
9586
+ });
9587
+ owl.onWillUnmount(() => this.chart?.destroy());
9588
+ owl.useEffect(() => {
9589
+ const runtime = this.chartRuntime;
9590
+ if (!deepEquals(runtime, this.currentRuntime, "ignoreFunctions")) {
9591
+ this.currentRuntime = runtime;
9592
+ this.updateChartJs(deepCopy(runtime));
9593
+ }
9571
9594
  });
9572
- owl.useEffect(() => this.updateChartJs(this.chartRuntime), () => [this.chartRuntime]);
9573
9595
  }
9574
9596
  createChart(chartData) {
9575
9597
  const canvas = this.canvas.el;
@@ -9589,7 +9611,7 @@ class ChartJsComponent extends owl.Component {
9589
9611
  this.chart.data.datasets = [];
9590
9612
  }
9591
9613
  this.chart.config.options = chartData.options;
9592
- this.chart.update("active");
9614
+ this.chart.update();
9593
9615
  }
9594
9616
  }
9595
9617
 
@@ -10078,8 +10100,7 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
10078
10100
  }
10079
10101
  getContextCreation() {
10080
10102
  return {
10081
- background: this.background,
10082
- title: this.title,
10103
+ ...this,
10083
10104
  range: this.keyValue ? [this.getters.getRangeString(this.keyValue, this.sheetId)] : undefined,
10084
10105
  auxiliaryRange: this.baseline
10085
10106
  ? this.getters.getRangeString(this.baseline, this.sheetId)
@@ -22211,7 +22232,7 @@ function truncateLabel(label) {
22211
22232
  /**
22212
22233
  * Get a default chart js configuration
22213
22234
  */
22214
- function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale }) {
22235
+ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, truncateLabels }) {
22215
22236
  const options = {
22216
22237
  // https://www.chartjs.org/docs/latest/general/responsive.html
22217
22238
  responsive: true, // will resize when its container is resized
@@ -22258,7 +22279,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale })
22258
22279
  type: chart.type,
22259
22280
  options,
22260
22281
  data: {
22261
- labels: labels.map(truncateLabel),
22282
+ labels: truncateLabels ? labels.map(truncateLabel) : labels,
22262
22283
  datasets: [],
22263
22284
  },
22264
22285
  platform: undefined, // This key is optional and will be set by chart.js
@@ -22438,25 +22459,23 @@ class BarChart extends AbstractChart {
22438
22459
  return {
22439
22460
  background: context.background,
22440
22461
  dataSets: context.range ? context.range : [],
22441
- dataSetsHaveTitle: false,
22442
- stacked: false,
22462
+ dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
22463
+ stacked: context.stacked ?? false,
22443
22464
  aggregated: context.aggregated ?? false,
22444
- legendPosition: "top",
22465
+ legendPosition: context.legendPosition ?? "top",
22445
22466
  title: context.title || "",
22446
22467
  type: "bar",
22447
- verticalAxisPosition: "left",
22468
+ verticalAxisPosition: context.verticalAxisPosition ?? "left",
22448
22469
  labelRange: context.auxiliaryRange || undefined,
22449
22470
  };
22450
22471
  }
22451
22472
  getContextCreation() {
22452
22473
  return {
22453
- background: this.background,
22454
- title: this.title,
22474
+ ...this,
22455
22475
  range: this.dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, this.sheetId)),
22456
22476
  auxiliaryRange: this.labelRange
22457
22477
  ? this.getters.getRangeString(this.labelRange, this.sheetId)
22458
22478
  : undefined,
22459
- aggregated: this.aggregated,
22460
22479
  };
22461
22480
  }
22462
22481
  copyForSheetId(sheetId) {
@@ -22621,13 +22640,11 @@ class ComboChart extends AbstractChart {
22621
22640
  }
22622
22641
  getContextCreation() {
22623
22642
  return {
22624
- background: this.background,
22625
- title: this.title,
22643
+ ...this,
22626
22644
  range: this.dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, this.sheetId)),
22627
22645
  auxiliaryRange: this.labelRange
22628
22646
  ? this.getters.getRangeString(this.labelRange, this.sheetId)
22629
22647
  : undefined,
22630
- aggregated: this.aggregated,
22631
22648
  };
22632
22649
  }
22633
22650
  getDefinition() {
@@ -22677,12 +22694,12 @@ class ComboChart extends AbstractChart {
22677
22694
  static getDefinitionFromContextCreation(context) {
22678
22695
  return {
22679
22696
  background: context.background,
22680
- dataSets: context.range ? context.range : [],
22681
- dataSetsHaveTitle: false,
22697
+ dataSets: context.range ?? [],
22698
+ dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
22682
22699
  aggregated: context.aggregated,
22683
- legendPosition: "top",
22700
+ legendPosition: context.legendPosition ?? "top",
22684
22701
  title: context.title || "",
22685
- verticalAxisPosition: "left",
22702
+ verticalAxisPosition: context.verticalAxisPosition ?? "left",
22686
22703
  labelRange: context.auxiliaryRange || undefined,
22687
22704
  type: "combo",
22688
22705
  useBothYAxis: false,
@@ -22933,8 +22950,7 @@ class GaugeChart extends AbstractChart {
22933
22950
  }
22934
22951
  getContextCreation() {
22935
22952
  return {
22936
- background: this.background,
22937
- title: this.title,
22953
+ ...this,
22938
22954
  range: this.dataRange
22939
22955
  ? [this.getters.getRangeString(this.dataRange, this.sheetId)]
22940
22956
  : undefined,
@@ -23222,9 +23238,9 @@ function isLuxonTimeAdapterInstalled() {
23222
23238
  }
23223
23239
  return isInstalled;
23224
23240
  }
23225
- function getLineOrScatterConfiguration(chart, labels, localeFormat) {
23241
+ function getLineOrScatterConfiguration(chart, labels, options) {
23226
23242
  const fontColor = chartFontColor(chart.background);
23227
- const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
23243
+ const config = getDefaultChartJsRuntime(chart, labels, fontColor, options);
23228
23244
  const legend = {
23229
23245
  labels: {
23230
23246
  color: fontColor,
@@ -23267,7 +23283,7 @@ function getLineOrScatterConfiguration(chart, labels, localeFormat) {
23267
23283
  value = Number(value);
23268
23284
  if (isNaN(value))
23269
23285
  return value;
23270
- const { locale, format } = localeFormat;
23286
+ const { locale, format } = options;
23271
23287
  return formatValue(value, {
23272
23288
  locale,
23273
23289
  format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
@@ -23300,9 +23316,10 @@ function createLineOrScatterChartRuntime(chart, getters) {
23300
23316
  ({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
23301
23317
  }
23302
23318
  const locale = getters.getLocale();
23319
+ const truncateLabels = axisType === "category";
23303
23320
  const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
23304
- const localeFormat = { format: dataSetFormat, locale };
23305
- const config = getLineOrScatterConfiguration(chart, labels, localeFormat);
23321
+ const options = { format: dataSetFormat, locale, truncateLabels };
23322
+ const config = getLineOrScatterConfiguration(chart, labels, options);
23306
23323
  const labelFormat = getChartLabelFormat(getters, chart.labelRange);
23307
23324
  if (axisType === "time") {
23308
23325
  const axis = {
@@ -23402,16 +23419,16 @@ class LineChart extends AbstractChart {
23402
23419
  return {
23403
23420
  background: context.background,
23404
23421
  dataSets: context.range ? context.range : [],
23405
- dataSetsHaveTitle: false,
23406
- labelsAsText: false,
23407
- legendPosition: "top",
23422
+ dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
23423
+ labelsAsText: context.labelsAsText ?? false,
23424
+ legendPosition: context.legendPosition ?? "top",
23408
23425
  title: context.title || "",
23409
23426
  type: "line",
23410
- verticalAxisPosition: "left",
23427
+ verticalAxisPosition: context.verticalAxisPosition ?? "left",
23411
23428
  labelRange: context.auxiliaryRange || undefined,
23412
- stacked: false,
23429
+ stacked: context.stacked ?? false,
23413
23430
  aggregated: context.aggregated ?? false,
23414
- cumulative: false,
23431
+ cumulative: context.cumulative ?? false,
23415
23432
  };
23416
23433
  }
23417
23434
  getDefinition() {
@@ -23437,13 +23454,11 @@ class LineChart extends AbstractChart {
23437
23454
  }
23438
23455
  getContextCreation() {
23439
23456
  return {
23440
- background: this.background,
23441
- title: this.title,
23457
+ ...this,
23442
23458
  range: this.dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, this.sheetId)),
23443
23459
  auxiliaryRange: this.labelRange
23444
23460
  ? this.getters.getRangeString(this.labelRange, this.sheetId)
23445
23461
  : undefined,
23446
- aggregated: this.aggregated,
23447
23462
  };
23448
23463
  }
23449
23464
  updateRanges(applyChange) {
@@ -23513,8 +23528,8 @@ class PieChart extends AbstractChart {
23513
23528
  return {
23514
23529
  background: context.background,
23515
23530
  dataSets: context.range ? context.range : [],
23516
- dataSetsHaveTitle: false,
23517
- legendPosition: "top",
23531
+ dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
23532
+ legendPosition: context.legendPosition ?? "top",
23518
23533
  title: context.title || "",
23519
23534
  type: "pie",
23520
23535
  labelRange: context.auxiliaryRange || undefined,
@@ -23526,13 +23541,11 @@ class PieChart extends AbstractChart {
23526
23541
  }
23527
23542
  getContextCreation() {
23528
23543
  return {
23529
- background: this.background,
23530
- title: this.title,
23544
+ ...this,
23531
23545
  range: this.dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, this.sheetId)),
23532
23546
  auxiliaryRange: this.labelRange
23533
23547
  ? this.getters.getRangeString(this.labelRange, this.sheetId)
23534
23548
  : undefined,
23535
- aggregated: this.aggregated,
23536
23549
  };
23537
23550
  }
23538
23551
  getDefinitionWithSpecificDataSets(dataSets, labelRange, targetSheetId) {
@@ -23717,12 +23730,12 @@ class ScatterChart extends AbstractChart {
23717
23730
  return {
23718
23731
  background: context.background,
23719
23732
  dataSets: context.range ? context.range : [],
23720
- dataSetsHaveTitle: false,
23721
- labelsAsText: false,
23722
- legendPosition: "top",
23733
+ dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
23734
+ labelsAsText: context.labelsAsText ?? false,
23735
+ legendPosition: context.legendPosition ?? "top",
23723
23736
  title: context.title || "",
23724
23737
  type: "scatter",
23725
- verticalAxisPosition: "left",
23738
+ verticalAxisPosition: context.verticalAxisPosition ?? "left",
23726
23739
  labelRange: context.auxiliaryRange || undefined,
23727
23740
  aggregated: context.aggregated ?? false,
23728
23741
  };
@@ -23748,13 +23761,11 @@ class ScatterChart extends AbstractChart {
23748
23761
  }
23749
23762
  getContextCreation() {
23750
23763
  return {
23751
- background: this.background,
23752
- title: this.title,
23764
+ ...this,
23753
23765
  range: this.dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, this.sheetId)),
23754
23766
  auxiliaryRange: this.labelRange
23755
23767
  ? this.getters.getRangeString(this.labelRange, this.sheetId)
23756
23768
  : undefined,
23757
- aggregated: this.aggregated,
23758
23769
  };
23759
23770
  }
23760
23771
  updateRanges(applyChange) {
@@ -23868,27 +23879,25 @@ class WaterfallChart extends AbstractChart {
23868
23879
  return {
23869
23880
  background: context.background,
23870
23881
  dataSets: context.range ? context.range : [],
23871
- dataSetsHaveTitle: false,
23882
+ dataSetsHaveTitle: context.dataSetsHaveTitle ?? false,
23872
23883
  aggregated: context.aggregated ?? false,
23873
- legendPosition: "top",
23884
+ legendPosition: context.legendPosition ?? "top",
23874
23885
  title: context.title || "",
23875
23886
  type: "waterfall",
23876
- verticalAxisPosition: "left",
23887
+ verticalAxisPosition: context.verticalAxisPosition ?? "left",
23877
23888
  labelRange: context.auxiliaryRange || undefined,
23878
- showSubTotals: true,
23879
- showConnectorLines: true,
23880
- firstValueAsSubtotal: false,
23889
+ showSubTotals: context.showSubTotals ?? false,
23890
+ showConnectorLines: context.showConnectorLines ?? true,
23891
+ firstValueAsSubtotal: context.firstValueAsSubtotal ?? false,
23881
23892
  };
23882
23893
  }
23883
23894
  getContextCreation() {
23884
23895
  return {
23885
- background: this.background,
23886
- title: this.title,
23896
+ ...this,
23887
23897
  range: this.dataSets.map((ds) => this.getters.getRangeString(ds.dataRange, this.sheetId)),
23888
23898
  auxiliaryRange: this.labelRange
23889
23899
  ? this.getters.getRangeString(this.labelRange, this.sheetId)
23890
23900
  : undefined,
23891
- aggregated: this.aggregated,
23892
23901
  };
23893
23902
  }
23894
23903
  copyForSheetId(sheetId) {
@@ -30920,9 +30929,26 @@ chartSidePanelComponentRegistry
30920
30929
 
30921
30930
  class MainChartPanelStore extends SpreadsheetStore {
30922
30931
  panel = "configuration";
30932
+ creationContext = {};
30923
30933
  activatePanel(panel) {
30924
30934
  this.panel = panel;
30925
30935
  }
30936
+ changeChartType(figureId, type) {
30937
+ this.creationContext = {
30938
+ ...this.creationContext,
30939
+ ...this.getters.getContextCreationChart(figureId),
30940
+ };
30941
+ const sheetId = this.getters.getFigureSheetId(figureId);
30942
+ if (!sheetId) {
30943
+ return;
30944
+ }
30945
+ const definition = getChartDefinitionFromContextCreation(this.creationContext, type);
30946
+ this.model.dispatch("UPDATE_CHART", {
30947
+ definition,
30948
+ id: figureId,
30949
+ sheetId,
30950
+ });
30951
+ }
30926
30952
  }
30927
30953
 
30928
30954
  css /* scss */ `
@@ -30992,16 +31018,7 @@ class ChartPanel extends owl.Component {
30992
31018
  if (!this.figureId) {
30993
31019
  return;
30994
31020
  }
30995
- const context = this.env.model.getters.getContextCreationChart(this.figureId);
30996
- if (!context) {
30997
- throw new Error("Chart not defined.");
30998
- }
30999
- const definition = getChartDefinitionFromContextCreation(context, type);
31000
- this.env.model.dispatch("UPDATE_CHART", {
31001
- definition,
31002
- id: this.figureId,
31003
- sheetId: this.env.model.getters.getFigureSheetId(this.figureId),
31004
- });
31021
+ this.store.changeChartType(this.figureId, type);
31005
31022
  }
31006
31023
  get chartPanel() {
31007
31024
  if (!this.figureId) {
@@ -33849,13 +33866,13 @@ function createTableStyleContextMenuActions(env, styleId) {
33849
33866
  id: "editTableStyle",
33850
33867
  name: _t("Edit table style"),
33851
33868
  execute: (env) => env.openSidePanel("TableStyleEditorPanel", { styleId }),
33852
- icon: "o-spreadsheet-Icon.EDIT_TABLE",
33869
+ icon: "o-spreadsheet-Icon.EDIT",
33853
33870
  },
33854
33871
  {
33855
33872
  id: "deleteTableStyle",
33856
33873
  name: _t("Delete table style"),
33857
33874
  execute: (env) => env.model.dispatch("REMOVE_TABLE_STYLE", { tableStyleId: styleId }),
33858
- icon: "o-spreadsheet-Icon.DELETE_TABLE",
33875
+ icon: "o-spreadsheet-Icon.TRASH",
33859
33876
  },
33860
33877
  ]);
33861
33878
  }
@@ -33940,10 +33957,46 @@ function drawTexts(ctx, tableStyle, colWidth, rowHeight) {
33940
33957
  ctx.restore();
33941
33958
  }
33942
33959
 
33960
+ css /* scss */ `
33961
+ .o-table-style-list-item {
33962
+ border: 1px solid transparent;
33963
+ &.selected {
33964
+ border: 1px solid #007eff;
33965
+ background: #f5f5f5;
33966
+ }
33967
+
33968
+ &:hover {
33969
+ background: #ddd;
33970
+ .o-table-style-edit-button {
33971
+ display: block !important;
33972
+ right: 0;
33973
+ top: 0;
33974
+ background: #fff;
33975
+ cursor: pointer;
33976
+ border: 1px solid #ddd;
33977
+ padding: 1px 1px 1px 2px;
33978
+ .o-icon {
33979
+ font-size: 12px;
33980
+ width: 12px;
33981
+ height: 12px;
33982
+ }
33983
+ }
33984
+ }
33985
+ }
33986
+ `;
33943
33987
  class TableStylePreview extends owl.Component {
33944
33988
  static template = "o-spreadsheet-TableStylePreview";
33945
- static props = { tableConfig: Object, tableStyle: { type: Object, optional: true } };
33989
+ static components = { Menu };
33990
+ static props = {
33991
+ tableConfig: Object,
33992
+ tableStyle: Object,
33993
+ class: String,
33994
+ styleId: { type: String, optional: true },
33995
+ selected: { type: Boolean, optional: true },
33996
+ onClick: { type: Function, optional: true },
33997
+ };
33946
33998
  canvasRef = owl.useRef("canvas");
33999
+ menu = owl.useState({ isOpen: false, position: null, menuItems: [] });
33947
34000
  setup() {
33948
34001
  owl.onWillUpdateProps((nextProps) => {
33949
34002
  if (!deepEquals(this.props.tableConfig, nextProps.tableConfig) ||
@@ -33961,6 +34014,34 @@ class TableStylePreview extends owl.Component {
33961
34014
  const computedStyle = getComputedTableStyle(props.tableConfig, props.tableStyle, 5, 5);
33962
34015
  drawPreviewTable(ctx, computedStyle, (width - 1) / 5, (height - 1) / 5);
33963
34016
  }
34017
+ onContextMenu(event) {
34018
+ if (!this.props.styleId) {
34019
+ return;
34020
+ }
34021
+ this.menu.menuItems = createTableStyleContextMenuActions(this.env, this.props.styleId);
34022
+ this.menu.isOpen = true;
34023
+ this.menu.position = { x: event.clientX, y: event.clientY };
34024
+ }
34025
+ closeMenu() {
34026
+ this.menu.isOpen = false;
34027
+ this.menu.position = null;
34028
+ this.menu.menuItems = [];
34029
+ }
34030
+ get styleName() {
34031
+ if (!this.props.styleId) {
34032
+ return "";
34033
+ }
34034
+ return this.env.model.getters.getTableStyle(this.props.styleId).displayName;
34035
+ }
34036
+ get isStyleEditable() {
34037
+ if (!this.props.styleId) {
34038
+ return false;
34039
+ }
34040
+ return this.env.model.getters.isTableStyleEditable(this.props.styleId);
34041
+ }
34042
+ editTableStyle() {
34043
+ this.env.openSidePanel("TableStyleEditorPanel", { styleId: this.props.styleId });
34044
+ }
33964
34045
  }
33965
34046
 
33966
34047
  css /* scss */ `
@@ -33992,22 +34073,10 @@ css /* scss */ `
33992
34073
  }
33993
34074
  }
33994
34075
  }
33995
-
33996
- .o-table-style-list-item {
33997
- border: 1px solid transparent;
33998
- &.selected {
33999
- border: 1px solid #007eff;
34000
- background: #f5f5f5;
34001
- }
34002
-
34003
- &:hover {
34004
- background: #ddd;
34005
- }
34006
- }
34007
34076
  `;
34008
34077
  class TableStylesPopover extends owl.Component {
34009
34078
  static template = "o-spreadsheet-TableStylesPopover";
34010
- static components = { Popover, TableStylePreview, Menu };
34079
+ static components = { Popover, TableStylePreview };
34011
34080
  static props = {
34012
34081
  tableConfig: Object,
34013
34082
  popoverProps: { type: Object, optional: true },
@@ -34037,25 +34106,12 @@ class TableStylesPopover extends owl.Component {
34037
34106
  ? this.env.model.getters.getTableStyle(this.props.selectedStyleId).category
34038
34107
  : "medium";
34039
34108
  }
34040
- getStyleName(styleId) {
34041
- return this.env.model.getters.getTableStyle(styleId).displayName;
34042
- }
34043
34109
  newTableStyle() {
34044
34110
  this.props.closePopover();
34045
34111
  this.env.openSidePanel("TableStyleEditorPanel", {
34046
34112
  onStylePicked: this.props.onStylePicked,
34047
34113
  });
34048
34114
  }
34049
- onContextMenu(event, styleId) {
34050
- this.menu.menuItems = createTableStyleContextMenuActions(this.env, styleId);
34051
- this.menu.isOpen = true;
34052
- this.menu.position = { x: event.clientX, y: event.clientY };
34053
- }
34054
- closeMenu() {
34055
- this.menu.isOpen = false;
34056
- this.menu.position = null;
34057
- this.menu.menuItems = [];
34058
- }
34059
34115
  }
34060
34116
 
34061
34117
  css /* scss */ `
@@ -34086,10 +34142,9 @@ css /* scss */ `
34086
34142
  `;
34087
34143
  class TableStylePicker extends owl.Component {
34088
34144
  static template = "o-spreadsheet-TableStylePicker";
34089
- static components = { TableStylesPopover, TableStylePreview, Menu };
34145
+ static components = { TableStylesPopover, TableStylePreview };
34090
34146
  static props = { table: Object };
34091
34147
  state = owl.useState({ popoverProps: undefined });
34092
- menu = owl.useState({ isOpen: false, position: null, menuItems: [] });
34093
34148
  getDisplayedTableStyles() {
34094
34149
  const allStyles = this.env.model.getters.getTableStyles();
34095
34150
  const selectedStyleCategory = allStyles[this.props.table.config.styleId].category;
@@ -34126,19 +34181,6 @@ class TableStylePicker extends owl.Component {
34126
34181
  closePopover() {
34127
34182
  this.state.popoverProps = undefined;
34128
34183
  }
34129
- getStyleName(styleId) {
34130
- return this.env.model.getters.getTableStyle(styleId).displayName;
34131
- }
34132
- onContextMenu(event, styleId) {
34133
- this.menu.menuItems = createTableStyleContextMenuActions(this.env, styleId);
34134
- this.menu.isOpen = true;
34135
- this.menu.position = { x: event.clientX, y: event.clientY };
34136
- }
34137
- closeMenu() {
34138
- this.menu.isOpen = false;
34139
- this.menu.position = null;
34140
- this.menu.menuItems = [];
34141
- }
34142
34184
  }
34143
34185
 
34144
34186
  css /* scss */ `
@@ -34329,17 +34371,6 @@ class TablePanel extends owl.Component {
34329
34371
 
34330
34372
  css /* scss */ `
34331
34373
  .o-table-style-editor-panel {
34332
- .o-color-preview {
34333
- width: 30px;
34334
- height: 15px;
34335
- margin-left: 2px;
34336
- outline: 1px solid #3d85c6;
34337
- outline-offset: 1px;
34338
- margin-right: 10px;
34339
-
34340
- cursor: pointer;
34341
- }
34342
-
34343
34374
  .o-table-style-list-item {
34344
34375
  margin: 1px 3px;
34345
34376
  padding: 3px 6px;
@@ -34349,11 +34380,16 @@ css /* scss */ `
34349
34380
  height: 61px;
34350
34381
  }
34351
34382
  }
34383
+
34384
+ .o-sidePanelButtons .o-delete:hover:enabled {
34385
+ color: #ffffff;
34386
+ background: #d94b4b;
34387
+ }
34352
34388
  }
34353
34389
  `;
34354
34390
  class TableStyleEditorPanel extends owl.Component {
34355
34391
  static template = "o-spreadsheet-TableStyleEditorPanel";
34356
- static components = { Section, ColorPickerWidget, TableStylePreview };
34392
+ static components = { Section, RoundColorPicker, TableStylePreview };
34357
34393
  static props = {
34358
34394
  onCloseSidePanel: Function,
34359
34395
  onStylePicked: { type: Function, optional: true },
@@ -34398,6 +34434,13 @@ class TableStyleEditorPanel extends owl.Component {
34398
34434
  onCancel() {
34399
34435
  this.props.onCloseSidePanel();
34400
34436
  }
34437
+ onDelete() {
34438
+ if (!this.props.styleId) {
34439
+ return;
34440
+ }
34441
+ this.env.model.dispatch("REMOVE_TABLE_STYLE", { tableStyleId: this.props.styleId });
34442
+ this.props.onCloseSidePanel();
34443
+ }
34401
34444
  get colorPreviewStyle() {
34402
34445
  return cssPropertiesToCss({ background: this.state.primaryColor });
34403
34446
  }
@@ -34856,29 +34899,27 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
34856
34899
  this.highlightStore.register(this);
34857
34900
  }
34858
34901
  get highlights() {
34859
- const zone = this.getHighlightZone();
34902
+ let zone;
34903
+ const position = this.model.getters.getActivePosition();
34904
+ const cell = this.getters.getEvaluatedCell(position);
34905
+ const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
34906
+ zone = spreader
34907
+ ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
34908
+ : this.model.getters.getSpreadZone(position, { ignoreSpillError: true });
34860
34909
  if (!zone) {
34861
34910
  return [];
34862
34911
  }
34863
- const sheetId = this.model.getters.getActiveSheetId();
34864
34912
  return [
34865
34913
  {
34866
- sheetId,
34914
+ sheetId: position.sheetId,
34867
34915
  zone,
34916
+ dashed: cell.value === CellErrorType.SpilledBlocked,
34868
34917
  color: "#17A2B8",
34869
34918
  noFill: true,
34870
34919
  thinLine: true,
34871
34920
  },
34872
34921
  ];
34873
34922
  }
34874
- getHighlightZone() {
34875
- const position = this.model.getters.getActivePosition();
34876
- const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
34877
- const spreadZone = spreader
34878
- ? this.model.getters.getSpreadZone(spreader)
34879
- : this.model.getters.getSpreadZone(position);
34880
- return spreadZone;
34881
- }
34882
34923
  }
34883
34924
 
34884
34925
  // -----------------------------------------------------------------------------
@@ -35334,7 +35375,8 @@ class DataValidationOverlay extends owl.Component {
35334
35375
  get checkBoxCellPositions() {
35335
35376
  return this.env.model.getters
35336
35377
  .getVisibleCellPositions()
35337
- .filter(this.env.model.getters.isCellValidCheckbox);
35378
+ .filter((position) => this.env.model.getters.isCellValidCheckbox(position) &&
35379
+ !this.env.model.getters.isFilterHeader(position));
35338
35380
  }
35339
35381
  get listIconsCellPositions() {
35340
35382
  if (this.env.model.getters.isReadonly()) {
@@ -35342,7 +35384,8 @@ class DataValidationOverlay extends owl.Component {
35342
35384
  }
35343
35385
  return this.env.model.getters
35344
35386
  .getVisibleCellPositions()
35345
- .filter(this.env.model.getters.cellHasListDataValidationIcon);
35387
+ .filter((position) => this.env.model.getters.cellHasListDataValidationIcon(position) &&
35388
+ !this.env.model.getters.isFilterHeader(position));
35346
35389
  }
35347
35390
  }
35348
35391
 
@@ -50254,11 +50297,13 @@ class Evaluator {
50254
50297
  getEvaluatedCell(position) {
50255
50298
  return this.evaluatedCells.get(position) || EMPTY_CELL;
50256
50299
  }
50257
- getSpreadZone(position) {
50300
+ getSpreadZone(position, options = { ignoreSpillError: false }) {
50258
50301
  if (!this.spreadingRelations.isArrayFormula(position)) {
50259
50302
  return undefined;
50260
50303
  }
50261
- if (this.evaluatedCells.get(position)?.type === CellValueType.error) {
50304
+ const evaluatedCell = this.evaluatedCells.get(position);
50305
+ if (evaluatedCell?.type === CellValueType.error &&
50306
+ !(options.ignoreSpillError && evaluatedCell?.value === CellErrorType.SpilledBlocked)) {
50262
50307
  return positionToZone(position);
50263
50308
  }
50264
50309
  const spreadPositions = Array.from(this.spreadingRelations.getArrayResultPositions(position));
@@ -50471,12 +50516,12 @@ class Evaluator {
50471
50516
  return;
50472
50517
  }
50473
50518
  if (enoughCols) {
50474
- throw new EvaluationError(_t("Result couldn't be automatically expanded. Please insert more rows."));
50519
+ throw new SplillBlockedError(_t("Result couldn't be automatically expanded. Please insert more rows."));
50475
50520
  }
50476
50521
  if (enoughRows) {
50477
- throw new EvaluationError(_t("Result couldn't be automatically expanded. Please insert more columns."));
50522
+ throw new SplillBlockedError(_t("Result couldn't be automatically expanded. Please insert more columns."));
50478
50523
  }
50479
- throw new EvaluationError(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
50524
+ throw new SplillBlockedError(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
50480
50525
  }
50481
50526
  updateSpreadRelation({ sheetId, col, row, }) {
50482
50527
  const arrayFormulaPosition = { sheetId, col, row };
@@ -50493,7 +50538,7 @@ class Evaluator {
50493
50538
  if (rawCell?.content ||
50494
50539
  this.getters.getEvaluatedCell(position).type !== CellValueType.empty) {
50495
50540
  this.blockedArrayFormulas.add(formulaPosition);
50496
- throw new EvaluationError(_t("Array result was not expanded because it would overwrite data in %s.", toXC(position.col, position.row)));
50541
+ throw new SplillBlockedError(_t("Array result was not expanded because it would overwrite data in %s.", toXC(position.col, position.row)));
50497
50542
  }
50498
50543
  this.blockedArrayFormulas.delete(formulaPosition);
50499
50544
  };
@@ -50791,8 +50836,8 @@ class EvaluationPlugin extends UIPlugin {
50791
50836
  /**
50792
50837
  * Return the spread zone the position is part of, if any
50793
50838
  */
50794
- getSpreadZone(position) {
50795
- return this.evaluator.getSpreadZone(position);
50839
+ getSpreadZone(position, options = { ignoreSpillError: false }) {
50840
+ return this.evaluator.getSpreadZone(position, options);
50796
50841
  }
50797
50842
  getArrayFormulaSpreadingOn(position) {
50798
50843
  return this.evaluator.getArrayFormulaSpreadingOn(position);
@@ -50832,7 +50877,7 @@ class EvaluationPlugin extends UIPlugin {
50832
50877
  ? getItemId(newFormat, data.formats)
50833
50878
  : exportedCellData.format;
50834
50879
  let content;
50835
- if (isFormula && formulaCell instanceof FormulaCellWithDependencies) {
50880
+ if (isExported && isFormula && formulaCell instanceof FormulaCellWithDependencies) {
50836
50881
  content = formulaCell.contentWithFixedReferences;
50837
50882
  }
50838
50883
  else {
@@ -64548,6 +64593,6 @@ exports.tokenColors = tokenColors;
64548
64593
  exports.tokenize = tokenize;
64549
64594
 
64550
64595
 
64551
- __info__.version = "17.3.0-alpha.6";
64552
- __info__.date = "2024-04-26T07:39:53.611Z";
64553
- __info__.hash = "f58a0d5";
64596
+ __info__.version = "17.3.0-alpha.7";
64597
+ __info__.date = "2024-05-07T10:42:47.288Z";
64598
+ __info__.hash = "853c266";