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