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