@odoo/o-spreadsheet 18.1.0-alpha.6 → 18.1.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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.1.0-alpha.6
6
- * @date 2024-11-28T09:06:59.527Z
7
- * @hash 875c901
5
+ * @version 18.1.0-alpha.7
6
+ * @date 2024-12-05T10:40:26.512Z
7
+ * @hash 7b1c39b
8
8
  */
9
9
 
10
10
  'use strict';
@@ -172,10 +172,13 @@ const ALERT_INFO_BG = "#CDEDF1";
172
172
  const ALERT_INFO_BORDER = "#98DBE2";
173
173
  const ALERT_INFO_TEXT_COLOR = "#09414A";
174
174
  const BADGE_SELECTED_COLOR = "#E6F2F3";
175
- const DEFAULT_CHART_PADDING = 20;
176
- const DEFAULT_CHART_FONT_SIZE = 22;
177
- const SCORECARD_GAUGE_CHART_PADDING = 10;
178
- const SCORECARD_GAUGE_CHART_FONT_SIZE = 14;
175
+ const CHART_PADDING$1 = 20;
176
+ const CHART_PADDING_BOTTOM = 10;
177
+ const CHART_PADDING_TOP = 15;
178
+ const CHART_TITLE_FONT_SIZE = 16;
179
+ const CHART_AXIS_TITLE_FONT_SIZE = 12;
180
+ const SCORECARD_CHART_TITLE_FONT_SIZE = 14;
181
+ const PIVOT_TOKEN_COLOR = "#F28C28";
179
182
  // Color picker defaults as upper case HEX to match `toHex`helper
180
183
  const COLOR_PICKER_DEFAULTS = [
181
184
  "#000000",
@@ -335,8 +338,8 @@ const DEFAULT_WINDOW_SIZE = 2;
335
338
  const DEBOUNCE_TIME = 200;
336
339
  const MESSAGE_VERSION = 1;
337
340
  // Sheets
338
- const FORBIDDEN_SHEET_CHARS = ["'", "*", "?", "/", "\\", "[", "]"];
339
- const FORBIDDEN_IN_EXCEL_REGEX = /'|\*|\?|\/|\\|\[|\]/;
341
+ const FORBIDDEN_SHEETNAME_CHARS = ["'", "*", "?", "/", "\\", "[", "]"];
342
+ const FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX = /'|\*|\?|\/|\\|\[|\]/;
340
343
  // Cells
341
344
  const FORMULA_REF_IDENTIFIER = "|";
342
345
  // Components
@@ -389,6 +392,7 @@ const DEFAULT_CURRENCY = {
389
392
  //------------------------------------------------------------------------------
390
393
  // Miscellaneous
391
394
  //------------------------------------------------------------------------------
395
+ const sanitizeSheetNameRegex = new RegExp(FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX, "g");
392
396
  /**
393
397
  * Remove quotes from a quoted string
394
398
  * ```js
@@ -484,6 +488,10 @@ function getCanonicalSymbolName(symbolName) {
484
488
  }
485
489
  return symbolName;
486
490
  }
491
+ /** Replace the excel-excluded characters of a sheetName */
492
+ function sanitizeSheetName(sheetName, replacementChar = " ") {
493
+ return sheetName.replace(sanitizeSheetNameRegex, replacementChar);
494
+ }
487
495
  function clip(val, min, max) {
488
496
  return val < min ? min : val > max ? max : val;
489
497
  }
@@ -9516,6 +9524,12 @@ function chartFontColor(backgroundColor) {
9516
9524
  }
9517
9525
  return relativeLuminance(backgroundColor) < 0.3 ? "#FFFFFF" : "#000000";
9518
9526
  }
9527
+ function chartMutedFontColor(backgroundColor) {
9528
+ if (!backgroundColor) {
9529
+ return "#666666";
9530
+ }
9531
+ return relativeLuminance(backgroundColor) < 0.3 ? "#C8C8C8" : "#666666";
9532
+ }
9519
9533
  function checkDataset(definition) {
9520
9534
  if (definition.dataSets) {
9521
9535
  const invalidRanges = definition.dataSets.find((range) => !rangeReference.test(range.dataRange)) !== undefined;
@@ -9651,8 +9665,8 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
9651
9665
  const yMin = chart.chartArea.top;
9652
9666
  const textsPositions = {};
9653
9667
  for (const dataset of chart._metasets) {
9654
- if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
9655
- return; // ignore trend lines
9668
+ if (dataset.xAxisID === TREND_LINE_XAXIS_ID || dataset.hidden) {
9669
+ continue;
9656
9670
  }
9657
9671
  for (let i = 0; i < dataset._parsed.length; i++) {
9658
9672
  const parsedValue = dataset._parsed[i];
@@ -10099,7 +10113,7 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
10099
10113
  function drawScoreChart(structure, canvas) {
10100
10114
  const ctx = canvas.getContext("2d");
10101
10115
  canvas.width = structure.canvas.width;
10102
- const availableWidth = canvas.width - DEFAULT_CHART_PADDING;
10116
+ const availableWidth = canvas.width - CHART_PADDING$1 * 2;
10103
10117
  canvas.height = structure.canvas.height;
10104
10118
  ctx.fillStyle = structure.canvas.backgroundColor;
10105
10119
  ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
@@ -10234,10 +10248,9 @@ function createScorecardChartRuntime(chart, getters) {
10234
10248
  }
10235
10249
 
10236
10250
  /* Padding at the border of the chart */
10237
- const CHART_PADDING = SCORECARD_GAUGE_CHART_PADDING;
10251
+ const CHART_PADDING = 10;
10238
10252
  const BOTTOM_PADDING_RATIO = 0.05;
10239
10253
  /* Maximum font sizes of each element */
10240
- const CHART_TITLE_FONT_SIZE = SCORECARD_GAUGE_CHART_FONT_SIZE;
10241
10254
  const KEY_VALUE_FONT_SIZE = 32;
10242
10255
  const BASELINE_MAX_FONT_SIZE = 16;
10243
10256
  function formatBaselineDescr(baselineDescr, baseline) {
@@ -10309,7 +10322,7 @@ class ScorecardChartConfigBuilder {
10309
10322
  : this.height - (this.height - titleHeight - baselineHeight) / 2 - CHART_PADDING,
10310
10323
  },
10311
10324
  };
10312
- const minimalBaselinePosition = baselineArrowSize + DEFAULT_CHART_PADDING;
10325
+ const minimalBaselinePosition = baselineArrowSize + CHART_PADDING * 2;
10313
10326
  if (structure.baseline.position.x < minimalBaselinePosition) {
10314
10327
  structure.baseline.position.x = minimalBaselinePosition;
10315
10328
  }
@@ -10389,7 +10402,7 @@ class ScorecardChartConfigBuilder {
10389
10402
  return this.runtime.background;
10390
10403
  }
10391
10404
  get secondaryFontColor() {
10392
- return relativeLuminance(this.backgroundColor) > 0.3 ? "#525252" : "#C8C8C8";
10405
+ return chartMutedFontColor(this.backgroundColor);
10393
10406
  }
10394
10407
  getTextDimensions(text, font) {
10395
10408
  this.context.font = font;
@@ -10415,7 +10428,7 @@ class ScorecardChartConfigBuilder {
10415
10428
  }
10416
10429
  return {
10417
10430
  title: {
10418
- font: getDefaultContextFont(CHART_TITLE_FONT_SIZE, this.runtime.title.bold, this.runtime.title.italic),
10431
+ font: getDefaultContextFont(this.runtime.title.fontSize ?? SCORECARD_CHART_TITLE_FONT_SIZE, this.runtime.title.bold, this.runtime.title.italic),
10419
10432
  color: this.runtime.title.color ?? this.secondaryFontColor,
10420
10433
  },
10421
10434
  keyValue: {
@@ -21236,7 +21249,7 @@ function getFunctionsFromAST(ast, functionNames) {
21236
21249
 
21237
21250
  const PIVOT_FUNCTIONS = ["PIVOT.VALUE", "PIVOT.HEADER", "PIVOT"];
21238
21251
  /**
21239
- * Create a proposal entry for the compose autowcomplete
21252
+ * Create a proposal entry for the composer autocomplete
21240
21253
  * to insert a field name string in a formula.
21241
21254
  */
21242
21255
  function makeFieldProposal(field, granularity) {
@@ -22019,14 +22032,8 @@ const GAUGE_PADDING_BOTTOM = 20;
22019
22032
  const GAUGE_LABELS_FONT_SIZE = 12;
22020
22033
  const GAUGE_DEFAULT_VALUE_FONT_SIZE = 80;
22021
22034
  const GAUGE_BACKGROUND_COLOR = "#F3F2F1";
22022
- const GAUGE_TEXT_COLOR = "#666666";
22023
- const GAUGE_TEXT_COLOR_HIGH_CONTRAST = "#C8C8C8";
22024
- const GAUGE_INFLECTION_MARKER_COLOR = "#666666aa";
22025
22035
  const GAUGE_INFLECTION_LABEL_BOTTOM_MARGIN = 6;
22026
22036
  const GAUGE_TITLE_SECTION_HEIGHT = 25;
22027
- const GAUGE_TITLE_FONT_SIZE = SCORECARD_GAUGE_CHART_FONT_SIZE;
22028
- const GAUGE_TITLE_PADDING_LEFT = SCORECARD_GAUGE_CHART_PADDING;
22029
- const GAUGE_TITLE_PADDING_TOP = SCORECARD_GAUGE_CHART_PADDING;
22030
22037
  function drawGaugeChart(canvas, runtime) {
22031
22038
  const canvasBoundingRect = canvas.getBoundingClientRect();
22032
22039
  canvas.width = canvasBoundingRect.width;
@@ -22085,7 +22092,7 @@ function drawInflectionValues(ctx, config) {
22085
22092
  ctx.translate(rectX + width / 2 - 0.5, rectY + height - 0.5); // -0.5 for sharper lines. see RendererPlugin.drawBorders comment
22086
22093
  ctx.rotate(Math.PI / 2 - inflectionValue.rotation);
22087
22094
  ctx.lineWidth = 2;
22088
- ctx.strokeStyle = GAUGE_INFLECTION_MARKER_COLOR;
22095
+ ctx.strokeStyle = chartMutedFontColor(config.backgroundColor) + "aa";
22089
22096
  ctx.beginPath();
22090
22097
  ctx.moveTo(0, -(height - config.gauge.arcWidth));
22091
22098
  ctx.lineTo(0, -height - 3);
@@ -22139,22 +22146,22 @@ function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
22139
22146
  x: gaugeRect.x + gaugeRect.width - gaugeArcWidth / 2,
22140
22147
  y: gaugeRect.y + gaugeRect.height + GAUGE_LABELS_FONT_SIZE,
22141
22148
  };
22142
- const textColor = getContrastedTextColor(runtime.background);
22149
+ const textColor = chartMutedFontColor(runtime.background);
22143
22150
  const inflectionValues = getInflectionValues(runtime, gaugeRect, textColor, ctx);
22144
22151
  let x = 0, titleWidth = 0, titleHeight = 0;
22145
22152
  if (runtime.title.text) {
22146
- ({ width: titleWidth, height: titleHeight } = computeTextDimension(ctx, runtime.title.text, { ...runtime.title, fontSize: GAUGE_TITLE_FONT_SIZE }, "px"));
22153
+ ({ width: titleWidth, height: titleHeight } = computeTextDimension(ctx, runtime.title.text, { fontSize: CHART_TITLE_FONT_SIZE, ...runtime.title }, "px"));
22147
22154
  }
22148
22155
  switch (runtime.title.align) {
22149
22156
  case "right":
22150
- x = boundingRect.width - titleWidth - GAUGE_TITLE_PADDING_LEFT;
22157
+ x = boundingRect.width - titleWidth - CHART_PADDING$1;
22151
22158
  break;
22152
22159
  case "center":
22153
22160
  x = (boundingRect.width - titleWidth) / 2;
22154
22161
  break;
22155
22162
  case "left":
22156
22163
  default:
22157
- x = GAUGE_TITLE_PADDING_LEFT;
22164
+ x = CHART_PADDING$1;
22158
22165
  break;
22159
22166
  }
22160
22167
  return {
@@ -22162,10 +22169,10 @@ function getGaugeRenderingConfig(boundingRect, runtime, ctx) {
22162
22169
  height: boundingRect.height,
22163
22170
  title: {
22164
22171
  label: runtime.title.text ?? "",
22165
- fontSize: GAUGE_TITLE_FONT_SIZE,
22172
+ fontSize: runtime.title.fontSize ?? CHART_TITLE_FONT_SIZE,
22166
22173
  textPosition: {
22167
22174
  x,
22168
- y: GAUGE_TITLE_PADDING_TOP + titleHeight / 2,
22175
+ y: CHART_PADDING_TOP + titleHeight / 2,
22169
22176
  },
22170
22177
  color: runtime.title.color ?? textColor,
22171
22178
  bold: runtime.title.bold,
@@ -22282,11 +22289,6 @@ function getGaugeColor(runtime) {
22282
22289
  }
22283
22290
  return runtime.colors.at(-1);
22284
22291
  }
22285
- function getContrastedTextColor(backgroundColor) {
22286
- return relativeLuminance(backgroundColor) > 0.3
22287
- ? GAUGE_TEXT_COLOR
22288
- : GAUGE_TEXT_COLOR_HIGH_CONTRAST;
22289
- }
22290
22292
  function getSegmentsOfRectangle(rectangle) {
22291
22293
  return [
22292
22294
  { start: rectangle.topLeft, end: rectangle.topRight },
@@ -27000,13 +27002,12 @@ migrationStepRegistry
27000
27002
  versionFrom: "7",
27001
27003
  migrate(data) {
27002
27004
  const namesTaken = [];
27003
- const globalForbiddenInExcel = new RegExp(FORBIDDEN_IN_EXCEL_REGEX, "g");
27004
27005
  for (let sheet of data.sheets || []) {
27005
27006
  if (!sheet.name) {
27006
27007
  continue;
27007
27008
  }
27008
27009
  const oldName = sheet.name;
27009
- const escapedName = oldName.replace(globalForbiddenInExcel, "_");
27010
+ const escapedName = sanitizeSheetName(oldName, "_");
27010
27011
  let i = 1;
27011
27012
  let newName = escapedName;
27012
27013
  while (namesTaken.includes(newName)) {
@@ -28242,37 +28243,45 @@ function interpolateData(config, values, labels, newLabels) {
28242
28243
  const labelRange = labelMax - labelMin;
28243
28244
  const normalizedLabels = labels.map((v) => (v - labelMin) / labelRange);
28244
28245
  const normalizedNewLabels = newLabels.map((v) => (v - labelMin) / labelRange);
28245
- switch (config.type) {
28246
- case "polynomial": {
28247
- const order = config.order ?? 2;
28248
- if (order === 1) {
28249
- return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
28250
- }
28251
- const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
28252
- return normalizedNewLabels.map((v) => evaluatePolynomial(coeffs, v, order));
28253
- }
28254
- case "exponential": {
28255
- const positiveLogValues = [];
28256
- const filteredLabels = [];
28257
- for (let i = 0; i < values.length; i++) {
28258
- if (values[i] > 0) {
28259
- positiveLogValues.push(Math.log(values[i]));
28260
- filteredLabels.push(normalizedLabels[i]);
28246
+ try {
28247
+ switch (config.type) {
28248
+ case "polynomial": {
28249
+ const order = config.order;
28250
+ if (!order) {
28251
+ return Array.from({ length: newLabels.length }, () => NaN);
28252
+ }
28253
+ if (order === 1) {
28254
+ return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
28255
+ }
28256
+ const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
28257
+ return normalizedNewLabels.map((v) => evaluatePolynomial(coeffs, v, order));
28258
+ }
28259
+ case "exponential": {
28260
+ const positiveLogValues = [];
28261
+ const filteredLabels = [];
28262
+ for (let i = 0; i < values.length; i++) {
28263
+ if (values[i] > 0) {
28264
+ positiveLogValues.push(Math.log(values[i]));
28265
+ filteredLabels.push(normalizedLabels[i]);
28266
+ }
28261
28267
  }
28268
+ if (!filteredLabels.length) {
28269
+ return Array.from({ length: newLabels.length }, () => NaN);
28270
+ }
28271
+ return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0];
28262
28272
  }
28263
- if (!filteredLabels.length) {
28264
- return [];
28273
+ case "logarithmic": {
28274
+ return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0];
28265
28275
  }
28266
- return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0];
28267
- }
28268
- case "logarithmic": {
28269
- return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0];
28270
- }
28271
- case "trailingMovingAverage": {
28272
- return getMovingAverageValues(values, config.window);
28276
+ case "trailingMovingAverage": {
28277
+ return getMovingAverageValues(values, config.window);
28278
+ }
28279
+ default:
28280
+ return Array.from({ length: newLabels.length }, () => NaN);
28273
28281
  }
28274
- default:
28275
- return [];
28282
+ }
28283
+ catch (e) {
28284
+ return Array.from({ length: newLabels.length }, () => NaN);
28276
28285
  }
28277
28286
  }
28278
28287
  function getChartAxisType(chart, labelRange, getters) {
@@ -28743,54 +28752,16 @@ function getChartColorsGenerator(definition, dataSetsSize) {
28743
28752
  return new ColorGenerator(dataSetsSize, definition.dataSets?.map((ds) => ds.backgroundColor) || []);
28744
28753
  }
28745
28754
 
28746
- function getCommonChartLayout(definition) {
28747
- // TODO FIXME: this is unused ATM. All the charts should probably use this instead oh whatever padding they are using now
28748
- // also look into how DEFAULT_CHART_PADDING is used in scorecards, it look strange
28755
+ function getChartLayout(definition) {
28749
28756
  return {
28750
28757
  padding: {
28751
- left: DEFAULT_CHART_PADDING,
28752
- right: DEFAULT_CHART_PADDING,
28753
- top: definition.title?.text ? DEFAULT_CHART_PADDING / 2 : DEFAULT_CHART_PADDING + 5,
28754
- bottom: DEFAULT_CHART_PADDING,
28758
+ left: CHART_PADDING$1,
28759
+ right: CHART_PADDING$1,
28760
+ top: CHART_PADDING_TOP,
28761
+ bottom: CHART_PADDING_BOTTOM,
28755
28762
  },
28756
28763
  };
28757
28764
  }
28758
- function getBarChartLayout(definition) {
28759
- return {
28760
- padding: computeChartPadding({
28761
- displayTitle: !!definition.title?.text,
28762
- displayLegend: definition.legendPosition === "top",
28763
- }),
28764
- };
28765
- }
28766
- function getLineChartLayout(definition) {
28767
- return {
28768
- padding: computeChartPadding({
28769
- displayTitle: !!definition.title?.text,
28770
- displayLegend: definition.legendPosition === "top",
28771
- }),
28772
- };
28773
- }
28774
- function getPieChartLayout(definition) {
28775
- return {
28776
- padding: { left: 20, right: 20, top: definition.title ? 10 : 25, bottom: 10 },
28777
- };
28778
- }
28779
- function getWaterfallChartLayout(definition) {
28780
- return {
28781
- padding: { left: 20, right: 20, top: definition.title ? 10 : 25, bottom: 10 },
28782
- };
28783
- }
28784
- function computeChartPadding({ displayTitle, displayLegend, }) {
28785
- let top = 25;
28786
- if (displayTitle) {
28787
- top = 0;
28788
- }
28789
- else if (displayLegend) {
28790
- top = 10;
28791
- }
28792
- return { left: 20, right: 20, top, bottom: 10 };
28793
- }
28794
28765
 
28795
28766
  function getLegendDisplayOptions(definition, args) {
28796
28767
  return {
@@ -28848,11 +28819,12 @@ function getScatterChartLegend(definition, args) {
28848
28819
  return {
28849
28820
  ...INTERACTIVE_LEGEND_CONFIG,
28850
28821
  ...getLegendDisplayOptions(definition),
28851
- labels: {
28852
- color: chartFontColor(definition.background),
28853
- boxHeight: 6,
28854
- usePointStyle: true,
28855
- },
28822
+ ...getCustomLegendLabels(chartFontColor(definition.background), {
28823
+ pointStyle: "circle",
28824
+ // the stroke is the border around the circle, so increasing its size with the chart's color reduce the size of the circle
28825
+ strokeStyle: definition.background || "#ffffff",
28826
+ lineWidth: 8,
28827
+ }),
28856
28828
  };
28857
28829
  }
28858
28830
  function getComboChartLegend(definition, args) {
@@ -28941,10 +28913,10 @@ const INTERACTIVE_LEGEND_CONFIG = {
28941
28913
  target.style.cursor = "default";
28942
28914
  },
28943
28915
  onClick: (event, legendItem, legend) => {
28944
- if (!legend.legendItems) {
28916
+ const index = legendItem.datasetIndex;
28917
+ if (!legend.legendItems || index === undefined) {
28945
28918
  return;
28946
28919
  }
28947
- const index = legend.legendItems.indexOf(legendItem);
28948
28920
  if (legend.chart.isDatasetVisible(index)) {
28949
28921
  legend.chart.hide(index);
28950
28922
  }
@@ -28960,15 +28932,29 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
28960
28932
  labels: {
28961
28933
  color: fontColor,
28962
28934
  usePointStyle: true,
28963
- generateLabels: (chart) => chart.data.datasets.map((dataset, index) => ({
28964
- text: dataset.label ?? "",
28965
- fontColor,
28966
- strokeStyle: dataset.borderColor,
28967
- fillStyle: dataset.backgroundColor,
28968
- hidden: !chart.isDatasetVisible(index),
28969
- pointStyle: dataset.type === "line" ? "line" : "rect",
28970
- ...legendLabelConfig,
28971
- })),
28935
+ generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
28936
+ if (dataset["xAxisID"] === TREND_LINE_XAXIS_ID) {
28937
+ return {
28938
+ text: dataset.label ?? "",
28939
+ fontColor,
28940
+ strokeStyle: dataset.borderColor,
28941
+ hidden: !chart.isDatasetVisible(index),
28942
+ pointStyle: "line",
28943
+ datasetIndex: index,
28944
+ lineWidth: 3,
28945
+ };
28946
+ }
28947
+ return {
28948
+ text: dataset.label ?? "",
28949
+ fontColor,
28950
+ strokeStyle: dataset.borderColor,
28951
+ fillStyle: dataset.backgroundColor,
28952
+ hidden: !chart.isDatasetVisible(index),
28953
+ pointStyle: dataset.type === "line" ? "line" : "rect",
28954
+ datasetIndex: index,
28955
+ ...legendLabelConfig,
28956
+ };
28957
+ }),
28972
28958
  },
28973
28959
  };
28974
28960
  }
@@ -29116,6 +29102,7 @@ function getChartAxisTitleRuntime(design) {
29116
29102
  font: {
29117
29103
  style: italic ? "italic" : "normal",
29118
29104
  weight: bold ? "bold" : "normal",
29105
+ size: design.title.fontSize ?? CHART_AXIS_TITLE_FONT_SIZE,
29119
29106
  },
29120
29107
  align: align === "left" ? "start" : align === "right" ? "end" : "center",
29121
29108
  };
@@ -29181,17 +29168,22 @@ function getChartShowValues(definition, args) {
29181
29168
 
29182
29169
  function getChartTitle(definition) {
29183
29170
  const chartTitle = definition.title;
29184
- const fontColor = chartFontColor(definition.background);
29171
+ const fontColor = chartMutedFontColor(definition.background);
29185
29172
  return {
29186
29173
  display: !!chartTitle.text,
29187
29174
  text: _t(chartTitle.text),
29188
29175
  color: chartTitle?.color ?? fontColor,
29189
29176
  align: chartTitle.align === "center" ? "center" : chartTitle.align === "right" ? "end" : "start",
29190
29177
  font: {
29191
- size: DEFAULT_CHART_FONT_SIZE,
29178
+ size: definition.title.fontSize ?? CHART_TITLE_FONT_SIZE,
29192
29179
  weight: chartTitle.bold ? "bold" : "normal",
29193
29180
  style: chartTitle.italic ? "italic" : "normal",
29194
29181
  },
29182
+ padding: {
29183
+ // Disable title top/left/right padding to use the chart padding instead.
29184
+ // The legend already has a top padding, so bottom padding is useless for the title there.
29185
+ bottom: definition.legendPosition === "top" ? 0 : CHART_PADDING$1,
29186
+ },
29195
29187
  };
29196
29188
  }
29197
29189
 
@@ -29338,26 +29330,23 @@ var CHART_RUNTIME_HELPERS = /*#__PURE__*/Object.freeze({
29338
29330
  canChartParseLabels: canChartParseLabels,
29339
29331
  getBarChartData: getBarChartData,
29340
29332
  getBarChartDatasets: getBarChartDatasets,
29341
- getBarChartLayout: getBarChartLayout,
29342
29333
  getBarChartLegend: getBarChartLegend,
29343
29334
  getBarChartScales: getBarChartScales,
29344
29335
  getBarChartTooltip: getBarChartTooltip,
29345
29336
  getChartLabelFormat: getChartLabelFormat,
29337
+ getChartLayout: getChartLayout,
29346
29338
  getChartShowValues: getChartShowValues,
29347
29339
  getChartTitle: getChartTitle,
29348
29340
  getComboChartDatasets: getComboChartDatasets,
29349
29341
  getComboChartLegend: getComboChartLegend,
29350
- getCommonChartLayout: getCommonChartLayout,
29351
29342
  getData: getData,
29352
29343
  getLineChartData: getLineChartData,
29353
29344
  getLineChartDatasets: getLineChartDatasets,
29354
- getLineChartLayout: getLineChartLayout,
29355
29345
  getLineChartLegend: getLineChartLegend,
29356
29346
  getLineChartScales: getLineChartScales,
29357
29347
  getLineChartTooltip: getLineChartTooltip,
29358
29348
  getPieChartData: getPieChartData,
29359
29349
  getPieChartDatasets: getPieChartDatasets,
29360
- getPieChartLayout: getPieChartLayout,
29361
29350
  getPieChartLegend: getPieChartLegend,
29362
29351
  getPieChartTooltip: getPieChartTooltip,
29363
29352
  getPyramidChartData: getPyramidChartData,
@@ -29373,7 +29362,6 @@ var CHART_RUNTIME_HELPERS = /*#__PURE__*/Object.freeze({
29373
29362
  getScatterChartScales: getScatterChartScales,
29374
29363
  getTrendDatasetForBarChart: getTrendDatasetForBarChart,
29375
29364
  getTrendDatasetForLineChart: getTrendDatasetForLineChart,
29376
- getWaterfallChartLayout: getWaterfallChartLayout,
29377
29365
  getWaterfallChartLegend: getWaterfallChartLegend,
29378
29366
  getWaterfallChartScales: getWaterfallChartScales,
29379
29367
  getWaterfallChartTooltip: getWaterfallChartTooltip,
@@ -29521,7 +29509,7 @@ function createBarChartRuntime(chart, getters) {
29521
29509
  options: {
29522
29510
  ...CHART_COMMON_OPTIONS,
29523
29511
  indexAxis: chart.horizontal ? "y" : "x",
29524
- layout: getBarChartLayout(definition),
29512
+ layout: getChartLayout(),
29525
29513
  scales: getBarChartScales(definition, chartData),
29526
29514
  plugins: {
29527
29515
  title: getChartTitle(definition),
@@ -29673,7 +29661,7 @@ function createComboChartRuntime(chart, getters) {
29673
29661
  },
29674
29662
  options: {
29675
29663
  ...CHART_COMMON_OPTIONS,
29676
- layout: getBarChartLayout(definition),
29664
+ layout: getChartLayout(),
29677
29665
  scales: getBarChartScales(definition, chartData),
29678
29666
  plugins: {
29679
29667
  title: getChartTitle(definition),
@@ -30074,7 +30062,7 @@ function createLineChartRuntime(chart, getters) {
30074
30062
  },
30075
30063
  options: {
30076
30064
  ...CHART_COMMON_OPTIONS,
30077
- layout: getLineChartLayout(definition),
30065
+ layout: getChartLayout(),
30078
30066
  scales: getLineChartScales(definition, chartData),
30079
30067
  plugins: {
30080
30068
  title: getChartTitle(definition),
@@ -30209,7 +30197,7 @@ function createPieChartRuntime(chart, getters) {
30209
30197
  },
30210
30198
  options: {
30211
30199
  ...CHART_COMMON_OPTIONS,
30212
- layout: getPieChartLayout(definition),
30200
+ layout: getChartLayout(),
30213
30201
  plugins: {
30214
30202
  title: getChartTitle(definition),
30215
30203
  legend: getPieChartLegend(definition, chartData),
@@ -30346,7 +30334,7 @@ function createPyramidChartRuntime(chart, getters) {
30346
30334
  options: {
30347
30335
  ...CHART_COMMON_OPTIONS,
30348
30336
  indexAxis: "y",
30349
- layout: getBarChartLayout(definition),
30337
+ layout: getChartLayout(),
30350
30338
  scales: getPyramidChartScales(definition, chartData),
30351
30339
  plugins: {
30352
30340
  title: getChartTitle(definition),
@@ -30495,7 +30483,7 @@ function createRadarChartRuntime(chart, getters) {
30495
30483
  },
30496
30484
  options: {
30497
30485
  ...CHART_COMMON_OPTIONS,
30498
- layout: getBarChartLayout(definition),
30486
+ layout: getChartLayout(),
30499
30487
  scales: getRadarChartScales(definition, chartData),
30500
30488
  plugins: {
30501
30489
  title: getChartTitle(definition),
@@ -30648,7 +30636,7 @@ function createScatterChartRuntime(chart, getters) {
30648
30636
  },
30649
30637
  options: {
30650
30638
  ...CHART_COMMON_OPTIONS,
30651
- layout: getLineChartLayout(definition),
30639
+ layout: getChartLayout(),
30652
30640
  scales: getScatterChartScales(definition, chartData),
30653
30641
  plugins: {
30654
30642
  title: getChartTitle(definition),
@@ -30809,7 +30797,7 @@ function createWaterfallChartRuntime(chart, getters) {
30809
30797
  },
30810
30798
  options: {
30811
30799
  ...CHART_COMMON_OPTIONS,
30812
- layout: getWaterfallChartLayout(definition),
30800
+ layout: getChartLayout(),
30813
30801
  scales: getWaterfallChartScales(definition, chartData),
30814
30802
  plugins: {
30815
30803
  title: getChartTitle(definition),
@@ -33119,6 +33107,7 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
33119
33107
  adaptChartRange: adaptChartRange,
33120
33108
  chartFactory: chartFactory,
33121
33109
  chartFontColor: chartFontColor,
33110
+ chartMutedFontColor: chartMutedFontColor,
33122
33111
  chartRuntimeFactory: chartRuntimeFactory,
33123
33112
  chartToImage: chartToImage,
33124
33113
  checkDataset: checkDataset,
@@ -37411,6 +37400,95 @@ class ColorPickerWidget extends owl.Component {
37411
37400
  }
37412
37401
  }
37413
37402
 
37403
+ css /* scss */ `
37404
+ .o-font-size-editor {
37405
+ height: calc(100% - 4px);
37406
+ input.o-font-size {
37407
+ outline-color: ${SELECTION_BORDER_COLOR};
37408
+ height: 20px;
37409
+ width: 23px;
37410
+ }
37411
+ }
37412
+ .o-text-options > div {
37413
+ cursor: pointer;
37414
+ line-height: 26px;
37415
+ padding: 3px 12px;
37416
+ &:hover {
37417
+ background-color: rgba(0, 0, 0, 0.08);
37418
+ }
37419
+ }
37420
+ `;
37421
+ class FontSizeEditor extends owl.Component {
37422
+ static template = "o-spreadsheet-FontSizeEditor";
37423
+ static props = {
37424
+ currentFontSize: Number,
37425
+ onFontSizeChanged: Function,
37426
+ onToggle: { type: Function, optional: true },
37427
+ class: String,
37428
+ };
37429
+ static components = { Popover };
37430
+ fontSizes = FONT_SIZES;
37431
+ dropdown = owl.useState({ isOpen: false });
37432
+ inputRef = owl.useRef("inputFontSize");
37433
+ rootEditorRef = owl.useRef("FontSizeEditor");
37434
+ fontSizeListRef = owl.useRef("fontSizeList");
37435
+ setup() {
37436
+ owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
37437
+ }
37438
+ get popoverProps() {
37439
+ const { x, y, width, height } = this.rootEditorRef.el.getBoundingClientRect();
37440
+ return {
37441
+ anchorRect: { x, y, width, height },
37442
+ positioning: "BottomLeft",
37443
+ verticalOffset: 0,
37444
+ };
37445
+ }
37446
+ onExternalClick(ev) {
37447
+ if (!isChildEvent(this.fontSizeListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
37448
+ this.closeFontList();
37449
+ }
37450
+ }
37451
+ toggleFontList() {
37452
+ const isOpen = this.dropdown.isOpen;
37453
+ if (!isOpen) {
37454
+ this.props.onToggle?.();
37455
+ this.inputRef.el.focus();
37456
+ }
37457
+ else {
37458
+ this.closeFontList();
37459
+ }
37460
+ }
37461
+ closeFontList() {
37462
+ this.dropdown.isOpen = false;
37463
+ }
37464
+ setSize(fontSizeStr) {
37465
+ const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
37466
+ this.props.onFontSizeChanged(fontSize);
37467
+ this.closeFontList();
37468
+ }
37469
+ setSizeFromInput(ev) {
37470
+ this.setSize(ev.target.value);
37471
+ }
37472
+ setSizeFromList(fontSizeStr) {
37473
+ this.setSize(fontSizeStr);
37474
+ }
37475
+ onInputFocused(ev) {
37476
+ this.dropdown.isOpen = true;
37477
+ ev.target.select();
37478
+ }
37479
+ onInputKeydown(ev) {
37480
+ if (ev.key === "Enter" || ev.key === "Escape") {
37481
+ this.closeFontList();
37482
+ const target = ev.target;
37483
+ // In the case of a ESCAPE key, we get the previous font size back
37484
+ if (ev.key === "Escape") {
37485
+ target.value = `${this.props.currentFontSize}`;
37486
+ }
37487
+ this.props.onToggle?.();
37488
+ }
37489
+ }
37490
+ }
37491
+
37414
37492
  css /* scss */ `
37415
37493
  .o-chart-title-designer {
37416
37494
  > span {
@@ -37445,7 +37523,7 @@ css /* scss */ `
37445
37523
  `;
37446
37524
  class ChartTitle extends owl.Component {
37447
37525
  static template = "o-spreadsheet.ChartTitle";
37448
- static components = { Section, ColorPickerWidget };
37526
+ static components = { Section, ColorPickerWidget, FontSizeEditor };
37449
37527
  static props = {
37450
37528
  title: { type: String, optional: true },
37451
37529
  updateTitle: Function,
@@ -37454,7 +37532,8 @@ class ChartTitle extends owl.Component {
37454
37532
  toggleBold: { type: Function, optional: true },
37455
37533
  updateAlignment: { type: Function, optional: true },
37456
37534
  updateColor: { type: Function, optional: true },
37457
- style: { type: Object, optional: true },
37535
+ style: Object,
37536
+ onFontSizeChanged: Function,
37458
37537
  };
37459
37538
  static defaultProps = {
37460
37539
  title: "",
@@ -37469,6 +37548,9 @@ class ChartTitle extends owl.Component {
37469
37548
  updateTitle(ev) {
37470
37549
  this.props.updateTitle(ev.target.value);
37471
37550
  }
37551
+ updateFontSize(fontSize) {
37552
+ this.props.onFontSizeChanged(fontSize);
37553
+ }
37472
37554
  toggleDropdownTool(tool, ev) {
37473
37555
  const isOpen = this.state.activeTool === tool;
37474
37556
  this.closeMenus();
@@ -37511,6 +37593,7 @@ class AxisDesignEditor extends owl.Component {
37511
37593
  return {
37512
37594
  color: "",
37513
37595
  align: "center",
37596
+ fontSize: CHART_AXIS_TITLE_FONT_SIZE,
37514
37597
  ...axisDesign.title,
37515
37598
  };
37516
37599
  }
@@ -37528,6 +37611,17 @@ class AxisDesignEditor extends owl.Component {
37528
37611
  };
37529
37612
  this.props.updateChart(this.props.figureId, { axesDesign });
37530
37613
  }
37614
+ updateAxisTitleFontSize(fontSize) {
37615
+ const axesDesign = this.props.definition.axesDesign ?? {};
37616
+ axesDesign[this.state.currentAxis] = {
37617
+ ...axesDesign[this.state.currentAxis],
37618
+ title: {
37619
+ ...(axesDesign[this.state.currentAxis]?.title ?? {}),
37620
+ fontSize,
37621
+ },
37622
+ };
37623
+ this.props.updateChart(this.props.figureId, { axesDesign });
37624
+ }
37531
37625
  toggleBoldAxisTitle() {
37532
37626
  const axesDesign = this.props.definition.axesDesign ?? {};
37533
37627
  const title = axesDesign[this.state.currentAxis]?.title ?? {};
@@ -37647,8 +37741,12 @@ class GeneralDesignEditor extends owl.Component {
37647
37741
  figureId: String,
37648
37742
  definition: Object,
37649
37743
  updateChart: Function,
37744
+ defaultChartTitleFontSize: { type: Number, optional: true },
37650
37745
  slots: { type: Object, optional: true },
37651
37746
  };
37747
+ static defaultProps = {
37748
+ defaultChartTitleFontSize: CHART_TITLE_FONT_SIZE,
37749
+ };
37652
37750
  state;
37653
37751
  setup() {
37654
37752
  this.state = owl.useState({
@@ -37674,6 +37772,7 @@ class GeneralDesignEditor extends owl.Component {
37674
37772
  get titleStyle() {
37675
37773
  return {
37676
37774
  align: "left",
37775
+ fontSize: this.props.defaultChartTitleFontSize,
37677
37776
  ...this.title,
37678
37777
  };
37679
37778
  }
@@ -37682,6 +37781,10 @@ class GeneralDesignEditor extends owl.Component {
37682
37781
  this.props.updateChart(this.props.figureId, { title });
37683
37782
  this.state.activeTool = "";
37684
37783
  }
37784
+ updateChartTitleFontSize(fontSize) {
37785
+ const title = { ...this.title, fontSize };
37786
+ this.props.updateChart(this.props.figureId, { title });
37787
+ }
37685
37788
  toggleBoldChartTitle() {
37686
37789
  let title = this.title;
37687
37790
  title = { ...title, bold: !title.bold };
@@ -37889,7 +37992,7 @@ class SeriesWithAxisDesignEditor extends owl.Component {
37889
37992
  case "polynomial":
37890
37993
  config = {
37891
37994
  type: "polynomial",
37892
- order: type === "linear" ? 1 : 2,
37995
+ order: type === "linear" ? 1 : this.getMaxPolynomialDegree(index),
37893
37996
  };
37894
37997
  break;
37895
37998
  case "exponential":
@@ -38349,6 +38452,9 @@ class ScorecardChartDesignPanel extends owl.Component {
38349
38452
  get humanizeNumbersLabel() {
38350
38453
  return _t("Humanize numbers");
38351
38454
  }
38455
+ get defaultScorecardTitleFontSize() {
38456
+ return SCORECARD_CHART_TITLE_FONT_SIZE;
38457
+ }
38352
38458
  updateHumanizeNumbers(humanize) {
38353
38459
  this.props.updateChart(this.props.figureId, { humanize });
38354
38460
  }
@@ -39812,6 +39918,15 @@ class StandaloneComposerStore extends AbstractComposerStore {
39812
39918
  confirmEdition(content) {
39813
39919
  this.args().onConfirm(content);
39814
39920
  }
39921
+ getTokenColor(token) {
39922
+ if (token.type === "SYMBOL") {
39923
+ const matchedColor = this.args().getContextualColoredSymbolToken?.(token);
39924
+ if (matchedColor) {
39925
+ return matchedColor;
39926
+ }
39927
+ }
39928
+ return super.getTokenColor(token);
39929
+ }
39815
39930
  }
39816
39931
 
39817
39932
  css /* scss */ `
@@ -39849,6 +39964,7 @@ class StandaloneComposer extends owl.Component {
39849
39964
  placeholder: { type: String, optional: true },
39850
39965
  class: { type: String, optional: true },
39851
39966
  invalid: { type: Boolean, optional: true },
39967
+ getContextualColoredSymbolToken: { type: Function, optional: true },
39852
39968
  };
39853
39969
  static components = { Composer };
39854
39970
  static defaultProps = {
@@ -39865,6 +39981,7 @@ class StandaloneComposer extends owl.Component {
39865
39981
  content: this.props.composerContent,
39866
39982
  contextualAutocomplete: this.props.contextualAutocomplete,
39867
39983
  defaultRangeSheetId: this.props.defaultRangeSheetId,
39984
+ getContextualColoredSymbolToken: this.props.getContextualColoredSymbolToken,
39868
39985
  }));
39869
39986
  this.standaloneComposerStore = standaloneComposerStore;
39870
39987
  this.composerInterface = {
@@ -43425,7 +43542,7 @@ function createMeasureAutoComplete(pivot, forComputedMeasure) {
43425
43542
  return {
43426
43543
  text: text,
43427
43544
  description: measure.displayName,
43428
- htmlContent: [{ value: text, color: tokenColors.FUNCTION }],
43545
+ htmlContent: [{ value: text, color: PIVOT_TOKEN_COLOR }],
43429
43546
  fuzzySearchKey: measure.displayName + text + measure.fieldName,
43430
43547
  };
43431
43548
  });
@@ -43434,7 +43551,7 @@ function createMeasureAutoComplete(pivot, forComputedMeasure) {
43434
43551
  return {
43435
43552
  text: text,
43436
43553
  description: dimension.displayName,
43437
- htmlContent: [{ value: text, color: tokenColors.FUNCTION }],
43554
+ htmlContent: [{ value: text, color: PIVOT_TOKEN_COLOR }],
43438
43555
  fuzzySearchKey: dimension.displayName + text + dimension.fieldName,
43439
43556
  };
43440
43557
  });
@@ -43514,6 +43631,18 @@ class PivotMeasureEditor extends owl.Component {
43514
43631
  measure: this.props.measure,
43515
43632
  });
43516
43633
  }
43634
+ getColoredSymbolToken(token) {
43635
+ if (token.type !== "SYMBOL") {
43636
+ return undefined;
43637
+ }
43638
+ const tokenValue = unquote(token.value, "'");
43639
+ if (this.props.definition.columns.some((col) => col.nameWithGranularity === tokenValue) ||
43640
+ this.props.definition.rows.some((row) => row.nameWithGranularity === tokenValue) ||
43641
+ this.props.definition.measures.some((measure) => measure.id === tokenValue && measure.id !== this.props.measure.id)) {
43642
+ return PIVOT_TOKEN_COLOR;
43643
+ }
43644
+ return undefined;
43645
+ }
43517
43646
  }
43518
43647
 
43519
43648
  css /* scss */ `
@@ -51888,7 +52017,7 @@ class CellPlugin extends CorePlugin {
51888
52017
  for (let col = zone.left; col <= zone.right; col++) {
51889
52018
  for (let row = zone.top; row <= zone.bottom; row++) {
51890
52019
  const cell = this.getters.getCell({ sheetId, col, row });
51891
- if (cell) {
52020
+ if (cell?.isFormula || cell?.content) {
51892
52021
  this.dispatch("UPDATE_CELL", {
51893
52022
  sheetId: sheetId,
51894
52023
  content: "",
@@ -51924,7 +52053,6 @@ class CellPlugin extends CorePlugin {
51924
52053
  for (let zone of recomputeZones(zones)) {
51925
52054
  for (let col = zone.left; col <= zone.right; col++) {
51926
52055
  for (let row = zone.top; row <= zone.bottom; row++) {
51927
- // commandHelpers.updateCell(sheetId, col, row, { style: undefined});
51928
52056
  this.dispatch("UPDATE_CELL", {
51929
52057
  sheetId,
51930
52058
  col,
@@ -55343,7 +55471,7 @@ class SheetPlugin extends CorePlugin {
55343
55471
  if (orderedSheetIds.find((id) => sheets[id]?.name.toLowerCase() === name && id !== cmd.sheetId)) {
55344
55472
  return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
55345
55473
  }
55346
- if (FORBIDDEN_IN_EXCEL_REGEX.test(name)) {
55474
+ if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
55347
55475
  return "ForbiddenCharactersInSheetName" /* CommandResult.ForbiddenCharactersInSheetName */;
55348
55476
  }
55349
55477
  return "Success" /* CommandResult.Success */;
@@ -60751,11 +60879,13 @@ class PivotUIPlugin extends UIPlugin {
60751
60879
  return EMPTY_PIVOT_CELL;
60752
60880
  }
60753
60881
  if (functionName === "PIVOT") {
60754
- const includeTotal = args[2] === false ? false : undefined;
60755
- const includeColumnHeaders = args[3] === false ? false : undefined;
60882
+ const includeTotal = toScalar(args[2]);
60883
+ const shouldIncludeTotal = includeTotal === undefined ? true : toBoolean(includeTotal);
60884
+ const includeColumnHeaders = toScalar(args[3]);
60885
+ const shouldIncludeColumnHeaders = includeColumnHeaders === undefined ? true : toBoolean(includeColumnHeaders);
60756
60886
  const pivotCells = pivot
60757
60887
  .getTableStructure()
60758
- .getPivotCells(includeTotal, includeColumnHeaders);
60888
+ .getPivotCells(shouldIncludeTotal, shouldIncludeColumnHeaders);
60759
60889
  const pivotCol = position.col - mainPosition.col;
60760
60890
  const pivotRow = position.row - mainPosition.row;
60761
60891
  return pivotCells[pivotCol][pivotRow];
@@ -62909,7 +63039,7 @@ class InsertPivotPlugin extends UIPlugin {
62909
63039
  getPivotDuplicateSheetName(pivotName) {
62910
63040
  let i = 1;
62911
63041
  const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
62912
- const sanitizedName = pivotName.replace(new RegExp(FORBIDDEN_IN_EXCEL_REGEX, "g"), " ");
63042
+ const sanitizedName = sanitizeSheetName(pivotName);
62913
63043
  let name = sanitizedName;
62914
63044
  while (names.includes(name)) {
62915
63045
  name = `${sanitizedName} (${i})`;
@@ -66985,7 +67115,7 @@ function interactiveRenameSheet(env, sheetId, name, errorCallback) {
66985
67115
  env.raiseError(_t("A sheet with the name %s already exists. Please select another name.", name), errorCallback);
66986
67116
  }
66987
67117
  else if (result.reasons.includes("ForbiddenCharactersInSheetName" /* CommandResult.ForbiddenCharactersInSheetName */)) {
66988
- env.raiseError(_t("Some used characters are not allowed in a sheet name (Forbidden characters are %s).", FORBIDDEN_SHEET_CHARS.join(" ")), errorCallback);
67118
+ env.raiseError(_t("Some used characters are not allowed in a sheet name (Forbidden characters are %s).", FORBIDDEN_SHEETNAME_CHARS.join(" ")), errorCallback);
66989
67119
  }
66990
67120
  }
66991
67121
 
@@ -68215,7 +68345,7 @@ class ActionButton extends owl.Component {
68215
68345
  setup() {
68216
68346
  owl.onWillUpdateProps((nextProps) => {
68217
68347
  if (nextProps.action !== this.props.action) {
68218
- this.actionButton = createAction(this.props.action);
68348
+ this.actionButton = createAction(nextProps.action);
68219
68349
  }
68220
68350
  });
68221
68351
  }
@@ -68551,88 +68681,6 @@ class TopBarComposer extends owl.Component {
68551
68681
  }
68552
68682
  }
68553
68683
 
68554
- css /* scss */ `
68555
- .o-font-size-editor {
68556
- height: calc(100% - 4px);
68557
- input.o-font-size {
68558
- outline-color: ${SELECTION_BORDER_COLOR};
68559
- height: 20px;
68560
- width: 23px;
68561
- }
68562
- }
68563
- .o-text-options > div {
68564
- cursor: pointer;
68565
- line-height: 26px;
68566
- padding: 3px 12px;
68567
- &:hover {
68568
- background-color: rgba(0, 0, 0, 0.08);
68569
- }
68570
- }
68571
- `;
68572
- class FontSizeEditor extends owl.Component {
68573
- static template = "o-spreadsheet-FontSizeEditor";
68574
- static props = {
68575
- onToggle: Function,
68576
- dropdownStyle: String,
68577
- class: String,
68578
- };
68579
- static components = {};
68580
- fontSizes = FONT_SIZES;
68581
- dropdown = owl.useState({ isOpen: false });
68582
- inputRef = owl.useRef("inputFontSize");
68583
- rootEditorRef = owl.useRef("FontSizeEditor");
68584
- setup() {
68585
- owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
68586
- }
68587
- onExternalClick(ev) {
68588
- if (!isChildEvent(this.rootEditorRef.el, ev)) {
68589
- this.closeFontList();
68590
- }
68591
- }
68592
- get currentFontSize() {
68593
- return this.env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
68594
- }
68595
- toggleFontList() {
68596
- const isOpen = this.dropdown.isOpen;
68597
- if (!isOpen) {
68598
- this.props.onToggle();
68599
- this.inputRef.el.focus();
68600
- }
68601
- else {
68602
- this.closeFontList();
68603
- }
68604
- }
68605
- closeFontList() {
68606
- this.dropdown.isOpen = false;
68607
- }
68608
- setSize(fontSizeStr) {
68609
- const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
68610
- setStyle(this.env, { fontSize });
68611
- this.closeFontList();
68612
- }
68613
- setSizeFromInput(ev) {
68614
- this.setSize(ev.target.value);
68615
- }
68616
- setSizeFromList(fontSizeStr) {
68617
- this.setSize(fontSizeStr);
68618
- }
68619
- onInputFocused(ev) {
68620
- this.dropdown.isOpen = true;
68621
- ev.target.select();
68622
- }
68623
- onInputKeydown(ev) {
68624
- if (ev.key === "Enter" || ev.key === "Escape") {
68625
- this.closeFontList();
68626
- const target = ev.target;
68627
- // In the case of a ESCAPE key, we get the previous font size back
68628
- if (ev.key === "Escape") {
68629
- target.value = `${this.currentFontSize}`;
68630
- }
68631
- this.props.onToggle();
68632
- }
68633
- }
68634
- }
68635
-
68636
68684
  class TableDropdownButton extends owl.Component {
68637
68685
  static template = "o-spreadsheet-TableDropdownButton";
68638
68686
  static components = { TableStylesPopover, ActionButton };
@@ -68801,9 +68849,6 @@ class TopBar extends owl.Component {
68801
68849
  onClick: Function,
68802
68850
  dropdownMaxHeight: Number,
68803
68851
  };
68804
- get dropdownStyle() {
68805
- return `max-height:${this.props.dropdownMaxHeight}px`;
68806
- }
68807
68852
  static components = {
68808
68853
  ColorPickerWidget,
68809
68854
  ColorPicker,
@@ -68841,6 +68886,9 @@ class TopBar extends owl.Component {
68841
68886
  .getAllOrdered()
68842
68887
  .filter((item) => !item.isVisible || item.isVisible(this.env));
68843
68888
  }
68889
+ get currentFontSize() {
68890
+ return this.env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
68891
+ }
68844
68892
  onExternalClick(ev) {
68845
68893
  // TODO : manage click events better. We need this piece of code
68846
68894
  // otherwise the event opening the menu would close it on the same frame.
@@ -68919,6 +68967,9 @@ class TopBar extends owl.Component {
68919
68967
  setStyle(this.env, { [target]: color });
68920
68968
  this.onClick();
68921
68969
  }
68970
+ setFontSize(fontSize) {
68971
+ setStyle(this.env, { fontSize });
68972
+ }
68922
68973
  }
68923
68974
 
68924
68975
  function instantiateClipboard() {
@@ -70919,12 +70970,11 @@ function createChart(chart, chartSheetIndex, data) {
70919
70970
  // <manualLayout/> to manually position the chart in the figure container
70920
70971
  let title = escapeXml ``;
70921
70972
  if (chart.data.title?.text) {
70922
- const color = chart.data.title.color
70923
- ? toXlsxHexColor(chart.data.title.color)
70924
- : chart.data.fontColor;
70973
+ const titleColor = toXlsxHexColor(chartMutedFontColor(chart.data.backgroundColor));
70974
+ const fontSize = chart.data.title.fontSize ?? CHART_TITLE_FONT_SIZE;
70925
70975
  title = escapeXml /*xml*/ `
70926
70976
  <c:title>
70927
- ${insertText(chart.data.title.text, color, DEFAULT_CHART_FONT_SIZE, chart.data.title)}
70977
+ ${insertText(chart.data.title.text, titleColor, fontSize, chart.data.title)}
70928
70978
  <c:overlay val="0" />
70929
70979
  </c:title>
70930
70980
  `;
@@ -71014,7 +71064,7 @@ function lineAttributes(params) {
71014
71064
  </a:ln>
71015
71065
  `;
71016
71066
  }
71017
- function insertText(text, fontColor = "000000", fontsize = DEFAULT_CHART_FONT_SIZE, style = {}) {
71067
+ function insertText(text, fontColor = "000000", fontsize = CHART_TITLE_FONT_SIZE, style = {}) {
71018
71068
  return escapeXml /*xml*/ `
71019
71069
  <c:tx>
71020
71070
  <c:rich>
@@ -71515,6 +71565,7 @@ function addAx(position, axisName, axId, crossAxId, title, defaultFontColor, del
71515
71565
  // Each Axis present inside a graph needs to be identified by an unsigned integer in order to be referenced by its crossAxis.
71516
71566
  // I.e. x-axis, will reference y-axis and vice-versa.
71517
71567
  const color = title?.color ? toXlsxHexColor(title.color) : defaultFontColor;
71568
+ const fontSize = title?.fontSize ?? CHART_AXIS_TITLE_FONT_SIZE;
71518
71569
  return escapeXml /*xml*/ `
71519
71570
  <${axisName}>
71520
71571
  <c:axId val="${axId}"/>
@@ -71530,7 +71581,7 @@ function addAx(position, axisName, axId, crossAxId, title, defaultFontColor, del
71530
71581
  <c:minorTickMark val="none" />
71531
71582
  <c:numFmt formatCode="General" sourceLinked="1" />
71532
71583
  <c:title>
71533
- ${insertText(title?.text ?? "", color, 10, title)}
71584
+ ${insertText(title?.text ?? "", color, fontSize, title)}
71534
71585
  </c:title>
71535
71586
  ${insertTextProperties(10, defaultFontColor)}
71536
71587
  </${axisName}>
@@ -73641,6 +73692,7 @@ const helpers = {
73641
73692
  createPivotFormula,
73642
73693
  areDomainArgsFieldsValid,
73643
73694
  splitReference,
73695
+ sanitizeSheetName,
73644
73696
  };
73645
73697
  const links = {
73646
73698
  isMarkdownLink,
@@ -73779,6 +73831,6 @@ exports.tokenColors = tokenColors;
73779
73831
  exports.tokenize = tokenize;
73780
73832
 
73781
73833
 
73782
- __info__.version = "18.1.0-alpha.6";
73783
- __info__.date = "2024-11-28T09:06:59.527Z";
73784
- __info__.hash = "875c901";
73834
+ __info__.version = "18.1.0-alpha.7";
73835
+ __info__.date = "2024-12-05T10:40:26.512Z";
73836
+ __info__.hash = "7b1c39b";