@odoo/o-spreadsheet 17.1.0-alpha.5 → 17.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 17.1.0-alpha.5
6
- * @date 2023-12-05T09:51:40.034Z
7
- * @hash c2823eb
5
+ * @version 17.1.0-alpha.7
6
+ * @date 2024-01-12T13:45:00.505Z
7
+ * @hash cbce1ed
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -328,13 +328,6 @@ const FONT_SIZES = [6, 7, 8, 9, 10, 11, 12, 14, 18, 24, 36];
328
328
  //------------------------------------------------------------------------------
329
329
  // Miscellaneous
330
330
  //------------------------------------------------------------------------------
331
- /**
332
- * Stringify an object, like JSON.stringify, except that the first level of keys
333
- * is ordered.
334
- */
335
- function stringify(obj) {
336
- return JSON.stringify(obj, Object.keys(obj).sort());
337
- }
338
331
  /**
339
332
  * Remove quotes from a quoted string
340
333
  * ```js
@@ -557,7 +550,7 @@ function isObjectEmptyRecursive(argument) {
557
550
  */
558
551
  function getItemId(item, itemsDic) {
559
552
  for (let [key, value] of Object.entries(itemsDic)) {
560
- if (stringify(value) === stringify(item)) {
553
+ if (deepEquals(value, item)) {
561
554
  return parseInt(key, 10);
562
555
  }
563
556
  }
@@ -1207,16 +1200,84 @@ function toXC(col, row, rangePart = { colFixed: false, rowFixed: false }) {
1207
1200
  // -----------------------------------------------------------------------------
1208
1201
  // Date Type
1209
1202
  // -----------------------------------------------------------------------------
1203
+ /**
1204
+ * A DateTime object that can be used to manipulate spreadsheet dates.
1205
+ * Conceptually, a spreadsheet date is simply a number with a date format,
1206
+ * and it is timezone-agnostic.
1207
+ * This DateTime object consistently uses UTC time to represent a naive date and time.
1208
+ */
1209
+ class DateTime {
1210
+ jsDate;
1211
+ constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
1212
+ this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
1213
+ }
1214
+ static fromTimestamp(timestamp) {
1215
+ const date = new Date(timestamp);
1216
+ return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
1217
+ }
1218
+ static now() {
1219
+ const now = new Date();
1220
+ return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
1221
+ }
1222
+ toString() {
1223
+ return this.jsDate.toString();
1224
+ }
1225
+ toLocaleDateString() {
1226
+ return this.jsDate.toLocaleDateString();
1227
+ }
1228
+ getTime() {
1229
+ return this.jsDate.getTime();
1230
+ }
1231
+ getFullYear() {
1232
+ return this.jsDate.getUTCFullYear();
1233
+ }
1234
+ getMonth() {
1235
+ return this.jsDate.getUTCMonth();
1236
+ }
1237
+ getDate() {
1238
+ return this.jsDate.getUTCDate();
1239
+ }
1240
+ getDay() {
1241
+ return this.jsDate.getUTCDay();
1242
+ }
1243
+ getHours() {
1244
+ return this.jsDate.getUTCHours();
1245
+ }
1246
+ getMinutes() {
1247
+ return this.jsDate.getUTCMinutes();
1248
+ }
1249
+ getSeconds() {
1250
+ return this.jsDate.getUTCSeconds();
1251
+ }
1252
+ setFullYear(year) {
1253
+ return this.jsDate.setUTCFullYear(year);
1254
+ }
1255
+ setMonth(month) {
1256
+ return this.jsDate.setUTCMonth(month);
1257
+ }
1258
+ setDate(date) {
1259
+ return this.jsDate.setUTCDate(date);
1260
+ }
1261
+ setHours(hours) {
1262
+ return this.jsDate.setUTCHours(hours);
1263
+ }
1264
+ setMinutes(minutes) {
1265
+ return this.jsDate.setUTCMinutes(minutes);
1266
+ }
1267
+ setSeconds(seconds) {
1268
+ return this.jsDate.setUTCSeconds(seconds);
1269
+ }
1270
+ }
1210
1271
  // -----------------------------------------------------------------------------
1211
1272
  // Parsing
1212
1273
  // -----------------------------------------------------------------------------
1213
- const INITIAL_1900_DAY = new Date(1899, 11, 30);
1274
+ const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
1214
1275
  const MS_PER_DAY = 24 * 60 * 60 * 1000;
1215
1276
  const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
1216
- const CURRENT_YEAR = new Date().getFullYear();
1217
- const CURRENT_MONTH = new Date().getMonth();
1218
- const INITIAL_JS_DAY = new Date(0);
1219
- const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY;
1277
+ const CURRENT_YEAR = DateTime.now().getFullYear();
1278
+ const CURRENT_MONTH = DateTime.now().getMonth();
1279
+ const INITIAL_JS_DAY = DateTime.fromTimestamp(0);
1280
+ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY.getTime() - INITIAL_1900_DAY.getTime();
1220
1281
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
1221
1282
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
1222
1283
  const dateSeparatorsRegex = /\/|-|\s/;
@@ -1277,7 +1338,7 @@ function _parseDateTime(str, locale) {
1277
1338
  return {
1278
1339
  value: date.value + time.value,
1279
1340
  format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
1280
- jsDate: new Date(date.jsDate.getFullYear() + time.jsDate.getFullYear() - 1899, date.jsDate.getMonth() + time.jsDate.getMonth() - 11, date.jsDate.getDate() + time.jsDate.getDate() - 30, date.jsDate.getHours() + time.jsDate.getHours(), date.jsDate.getMinutes() + time.jsDate.getMinutes(), date.jsDate.getSeconds() + time.jsDate.getSeconds()),
1341
+ jsDate: new DateTime(date.jsDate.getFullYear() + time.jsDate.getFullYear() - 1899, date.jsDate.getMonth() + time.jsDate.getMonth() - 11, date.jsDate.getDate() + time.jsDate.getDate() - 30, date.jsDate.getHours() + time.jsDate.getHours(), date.jsDate.getMinutes() + time.jsDate.getMinutes(), date.jsDate.getSeconds() + time.jsDate.getSeconds()),
1281
1342
  };
1282
1343
  }
1283
1344
  return date || time;
@@ -1353,12 +1414,12 @@ function parseDate(parts, separator) {
1353
1414
  // month + 1: months are 0-indexed in JS
1354
1415
  const leadingZero = (monthStr?.length === 2 && month + 1 < 10) || (dayStr?.length === 2 && day < 10);
1355
1416
  const fullYear = yearStr?.length !== 2;
1356
- const jsDate = new Date(year, month, day);
1417
+ const jsDate = new DateTime(year, month, day);
1357
1418
  if (jsDate.getMonth() !== month || jsDate.getDate() !== day) {
1358
1419
  // invalid date
1359
1420
  return null;
1360
1421
  }
1361
- const delta = jsDate - INITIAL_1900_DAY;
1422
+ const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
1362
1423
  const format = getFormatFromDateParts(parts, separator, leadingZero, fullYear);
1363
1424
  return {
1364
1425
  value: Math.round(delta / MS_PER_DAY),
@@ -1449,7 +1510,7 @@ function parseTime(str) {
1449
1510
  if (hours >= 24) {
1450
1511
  format = "hhhh:mm:ss";
1451
1512
  }
1452
- const jsDate = new Date(1899, 11, 30, hours, minutes, seconds);
1513
+ const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
1453
1514
  return {
1454
1515
  value: hours / 24 + minutes / 1440 + seconds / 86400,
1455
1516
  format: format,
@@ -1463,7 +1524,7 @@ function parseTime(str) {
1463
1524
  // -----------------------------------------------------------------------------
1464
1525
  function numberToJsDate(value) {
1465
1526
  const truncValue = Math.trunc(value);
1466
- let date = new Date(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
1527
+ let date = DateTime.fromTimestamp(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
1467
1528
  let time = value - truncValue;
1468
1529
  time = time < 0 ? 1 + time : time;
1469
1530
  const hours = Math.round(time * 24);
@@ -1483,7 +1544,7 @@ function jsDateToNumber(date) {
1483
1544
  }
1484
1545
  /** Return the number of days in the current month of the given date */
1485
1546
  function getDaysInMonth(date) {
1486
- return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
1547
+ return new DateTime(date.getFullYear(), date.getMonth() + 1, 0).getDate();
1487
1548
  }
1488
1549
  function isLastDayOfMonth(date) {
1489
1550
  return getDaysInMonth(date) === date.getDate();
@@ -1501,7 +1562,7 @@ function addMonthsToDate(date, months, keepEndOfMonth) {
1501
1562
  const yStart = date.getFullYear();
1502
1563
  const mStart = date.getMonth();
1503
1564
  const dStart = date.getDate();
1504
- const jsDate = new Date(yStart, mStart + months);
1565
+ const jsDate = new DateTime(yStart, mStart + months, 1);
1505
1566
  if (keepEndOfMonth && dStart === getDaysInMonth(date)) {
1506
1567
  jsDate.setDate(getDaysInMonth(jsDate));
1507
1568
  }
@@ -2060,6 +2121,8 @@ var CommandResult;
2060
2121
  CommandResult["NoChanges"] = "NoChanges";
2061
2122
  })(CommandResult || (CommandResult = {}));
2062
2123
 
2124
+ const PLAIN_TEXT_FORMAT = "@"; // see OpenXML spec §18.8.31
2125
+
2063
2126
  const DEFAULT_LOCALES = [
2064
2127
  {
2065
2128
  name: "English (US)",
@@ -2724,20 +2787,20 @@ function flattenRowFirst(items, callback) {
2724
2787
  }
2725
2788
 
2726
2789
  function toCriterionDateNumber(dateValue) {
2727
- const today = new Date();
2790
+ const today = DateTime.now();
2728
2791
  switch (dateValue) {
2729
2792
  case "today":
2730
2793
  return jsDateToNumber(today);
2731
2794
  case "yesterday":
2732
- return jsDateToNumber(new Date(today.setDate(today.getDate() - 1)));
2795
+ return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
2733
2796
  case "tomorrow":
2734
- return jsDateToNumber(new Date(today.setDate(today.getDate() + 1)));
2797
+ return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
2735
2798
  case "lastWeek":
2736
- return jsDateToNumber(new Date(today.setDate(today.getDate() - 7)));
2799
+ return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
2737
2800
  case "lastMonth":
2738
- return jsDateToNumber(new Date(today.setMonth(today.getMonth() - 1)));
2801
+ return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
2739
2802
  case "lastYear":
2740
- return jsDateToNumber(new Date(today.setFullYear(today.getFullYear() - 1)));
2803
+ return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
2741
2804
  }
2742
2805
  }
2743
2806
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -2823,6 +2886,9 @@ function parseFormat(formatString) {
2823
2886
  * Formats a cell value with its format.
2824
2887
  */
2825
2888
  function formatValue(value, { format, locale }) {
2889
+ if (format === PLAIN_TEXT_FORMAT) {
2890
+ return toString(value) || "";
2891
+ }
2826
2892
  switch (typeof value) {
2827
2893
  case "string":
2828
2894
  return value;
@@ -3095,7 +3161,7 @@ function formatJSTime(jsDate, format) {
3095
3161
  .map((p) => {
3096
3162
  switch (p) {
3097
3163
  case "hhhh":
3098
- const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY) / (60 * 60 * 1000));
3164
+ const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY.getTime()) / (60 * 60 * 1000));
3099
3165
  return helapsedHours.toString();
3100
3166
  case "hh":
3101
3167
  return hours.toString().padStart(2, "0");
@@ -4663,6 +4729,9 @@ function transformRangeData(range, executed) {
4663
4729
 
4664
4730
  class ChartJsComponent extends Component {
4665
4731
  static template = "o-spreadsheet-ChartJsComponent";
4732
+ static props = {
4733
+ figure: Object,
4734
+ };
4666
4735
  canvas = useRef("graphContainer");
4667
4736
  chart;
4668
4737
  get background() {
@@ -4715,9 +4784,6 @@ class ChartJsComponent extends Component {
4715
4784
  this.chart.update("active");
4716
4785
  }
4717
4786
  }
4718
- ChartJsComponent.props = {
4719
- figure: Object,
4720
- };
4721
4787
 
4722
4788
  /**
4723
4789
  * AbstractChart is the class from which every Chart should inherit.
@@ -5294,7 +5360,7 @@ function createScorecardChartRuntime(chart, getters) {
5294
5360
  };
5295
5361
  baselineCell = getters.getEvaluatedCell(baselinePosition);
5296
5362
  }
5297
- const background = getters.getBackgroundOfSingleCellChart(chart.background, chart.keyValue);
5363
+ const { background, fontColor } = getters.getStyleOfSingleCellChart(chart.background, chart.keyValue);
5298
5364
  const locale = getters.getLocale();
5299
5365
  return {
5300
5366
  title: _t(chart.title),
@@ -5303,7 +5369,7 @@ function createScorecardChartRuntime(chart, getters) {
5303
5369
  baselineArrow: getBaselineArrowDirection(baselineCell, keyValueCell, chart.baselineMode),
5304
5370
  baselineColor: getBaselineColor(baselineCell, chart.baselineMode, keyValueCell, chart.baselineColorUp, chart.baselineColorDown),
5305
5371
  baselineDescr: chart.baselineDescr ? _t(chart.baselineDescr) : "",
5306
- fontColor: chartFontColor(background),
5372
+ fontColor,
5307
5373
  background,
5308
5374
  baselineStyle: chart.baselineMode !== "percentage" && baseline
5309
5375
  ? getters.getCellStyle({
@@ -5568,6 +5634,9 @@ class KeyValueElement extends ScorecardScalableElement {
5568
5634
 
5569
5635
  class ScorecardChart extends Component {
5570
5636
  static template = "o-spreadsheet-ScorecardChart";
5637
+ static props = {
5638
+ figure: Object,
5639
+ };
5571
5640
  canvas = useRef("chartContainer");
5572
5641
  get runtime() {
5573
5642
  return this.env.model.getters.getChartRuntime(this.props.figure.id);
@@ -5585,9 +5654,6 @@ class ScorecardChart extends Component {
5585
5654
  drawScoreChart(config, canvas);
5586
5655
  }
5587
5656
  }
5588
- ScorecardChart.props = {
5589
- figure: Object,
5590
- };
5591
5657
 
5592
5658
  /**
5593
5659
  * Registry
@@ -5729,6 +5795,9 @@ function detectLink(value) {
5729
5795
  }
5730
5796
 
5731
5797
  function evaluateLiteral(content, localeFormat) {
5798
+ if (localeFormat.format === PLAIN_TEXT_FORMAT) {
5799
+ return textCell(content || "", localeFormat);
5800
+ }
5732
5801
  return createEvaluatedCell(parseLiteral(content || "", localeFormat.locale), localeFormat);
5733
5802
  }
5734
5803
  function parseLiteral(content, locale) {
@@ -5763,6 +5832,9 @@ function createEvaluatedCell(value, localeFormat) {
5763
5832
  }
5764
5833
  function _createEvaluatedCell(value, localeFormat) {
5765
5834
  try {
5835
+ if (localeFormat.format === PLAIN_TEXT_FORMAT) {
5836
+ return textCell(toString(value), localeFormat);
5837
+ }
5766
5838
  for (const builder of builders) {
5767
5839
  const evaluateCell = builder(value, localeFormat);
5768
5840
  if (evaluateCell) {
@@ -6260,11 +6332,11 @@ css /* scss */ `
6260
6332
  class ErrorToolTip extends Component {
6261
6333
  static maxSize = { maxHeight: ERROR_TOOLTIP_MAX_HEIGHT };
6262
6334
  static template = "o-spreadsheet-ErrorToolTip";
6335
+ static props = {
6336
+ errors: Array,
6337
+ onClosed: { type: Function, optional: true },
6338
+ };
6263
6339
  }
6264
- ErrorToolTip.props = {
6265
- errors: Array,
6266
- onClosed: { type: Function, optional: true },
6267
- };
6268
6340
  const ErrorToolTipPopoverBuilder = {
6269
6341
  onHover: (position, getters) => {
6270
6342
  const cell = getters.getEvaluatedCell(position);
@@ -6306,6 +6378,14 @@ css /*SCSS*/ `
6306
6378
  `;
6307
6379
  class FilterMenuValueItem extends Component {
6308
6380
  static template = "o-spreadsheet-FilterMenuValueItem";
6381
+ static props = {
6382
+ value: String,
6383
+ isChecked: Boolean,
6384
+ isSelected: Boolean,
6385
+ onMouseMove: Function,
6386
+ onClick: Function,
6387
+ scrolledTo: { type: String, optional: true },
6388
+ };
6309
6389
  itemRef = useRef("menuValueItem");
6310
6390
  setup() {
6311
6391
  onWillPatch(() => {
@@ -6323,17 +6403,9 @@ class FilterMenuValueItem extends Component {
6323
6403
  });
6324
6404
  }
6325
6405
  }
6326
- FilterMenuValueItem.props = {
6327
- value: String,
6328
- isChecked: Boolean,
6329
- isSelected: Boolean,
6330
- onMouseMove: Function,
6331
- onClick: Function,
6332
- scrolledTo: { type: String, optional: true },
6333
- };
6334
6406
 
6335
6407
  const FILTER_MENU_HEIGHT = 295;
6336
- const CSS$2 = css /* scss */ `
6408
+ const CSS = css /* scss */ `
6337
6409
  .o-filter-menu {
6338
6410
  box-sizing: border-box;
6339
6411
  padding: 8px 16px;
@@ -6429,9 +6501,12 @@ const CSS$2 = css /* scss */ `
6429
6501
  }
6430
6502
  `;
6431
6503
  class FilterMenu extends Component {
6432
- static size = { width: MENU_WIDTH, height: FILTER_MENU_HEIGHT };
6433
6504
  static template = "o-spreadsheet-FilterMenu";
6434
- static style = CSS$2;
6505
+ static props = {
6506
+ filterPosition: Object,
6507
+ onClosed: { type: Function, optional: true },
6508
+ };
6509
+ static style = CSS;
6435
6510
  static components = { FilterMenuValueItem };
6436
6511
  state = useState({
6437
6512
  values: [],
@@ -6583,10 +6658,6 @@ class FilterMenu extends Component {
6583
6658
  this.props.onClosed?.();
6584
6659
  }
6585
6660
  }
6586
- FilterMenu.props = {
6587
- filterPosition: Object,
6588
- onClosed: { type: Function, optional: true },
6589
- };
6590
6661
  const FilterMenuPopoverBuilder = {
6591
6662
  onOpen: (position, getters) => {
6592
6663
  return {
@@ -6598,6 +6669,7 @@ const FilterMenuPopoverBuilder = {
6598
6669
  },
6599
6670
  };
6600
6671
 
6672
+ const macRegex = /Mac/i;
6601
6673
  /**
6602
6674
  * Return true if the event was triggered from
6603
6675
  * a child element.
@@ -6649,7 +6721,7 @@ const letterRegex = /^[a-zA-Z]$/;
6649
6721
  */
6650
6722
  function keyboardEventToShortcutString(ev, mode = "key") {
6651
6723
  let keyDownString = "";
6652
- if (ev.ctrlKey && ev.key !== "Ctrl")
6724
+ if (isCtrlKey(ev) && ev.key !== "Ctrl")
6653
6725
  keyDownString += "Ctrl+";
6654
6726
  if (ev.metaKey)
6655
6727
  keyDownString += "Ctrl+";
@@ -6662,7 +6734,15 @@ function keyboardEventToShortcutString(ev, mode = "key") {
6662
6734
  return keyDownString;
6663
6735
  }
6664
6736
  function isMacOS() {
6665
- return navigator.userAgent.toUpperCase().indexOf("MAC") >= 0;
6737
+ return Boolean(macRegex.test(navigator.userAgent));
6738
+ }
6739
+ /**
6740
+ * @param {KeyboardEvent | MouseEvent} ev
6741
+ * @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
6742
+ * On Mac, this is the "meta" or "command" key.
6743
+ */
6744
+ function isCtrlKey(ev) {
6745
+ return isMacOS() ? ev.metaKey : ev.ctrlKey;
6666
6746
  }
6667
6747
 
6668
6748
  /**
@@ -6779,6 +6859,19 @@ css /* scss */ `
6779
6859
  `;
6780
6860
  class Popover extends Component {
6781
6861
  static template = "o-spreadsheet-Popover";
6862
+ static props = {
6863
+ anchorRect: Object,
6864
+ containerRect: { type: Object, optional: true },
6865
+ positioning: { type: String, optional: true },
6866
+ maxWidth: { type: Number, optional: true },
6867
+ maxHeight: { type: Number, optional: true },
6868
+ verticalOffset: { type: Number, optional: true },
6869
+ onMouseWheel: { type: Function, optional: true },
6870
+ onPopoverHidden: { type: Function, optional: true },
6871
+ onPopoverMoved: { type: Function, optional: true },
6872
+ zIndex: { type: Number, optional: true },
6873
+ slots: Object,
6874
+ };
6782
6875
  static defaultProps = {
6783
6876
  positioning: "BottomLeft",
6784
6877
  verticalOffset: 0,
@@ -6835,19 +6928,6 @@ class Popover extends Component {
6835
6928
  });
6836
6929
  }
6837
6930
  }
6838
- Popover.props = {
6839
- anchorRect: Object,
6840
- containerRect: { type: Object, optional: true },
6841
- positioning: { type: String, optional: true },
6842
- maxWidth: { type: Number, optional: true },
6843
- maxHeight: { type: Number, optional: true },
6844
- verticalOffset: { type: Number, optional: true },
6845
- onMouseWheel: { type: Function, optional: true },
6846
- onPopoverHidden: { type: Function, optional: true },
6847
- onPopoverMoved: { type: Function, optional: true },
6848
- zIndex: { type: Number, optional: true },
6849
- slots: Object,
6850
- };
6851
6931
  class PopoverPositionContext {
6852
6932
  anchorRect;
6853
6933
  containerRect;
@@ -7029,6 +7109,15 @@ css /* scss */ `
7029
7109
  `;
7030
7110
  class Menu extends Component {
7031
7111
  static template = "o-spreadsheet-Menu";
7112
+ static props = {
7113
+ position: Object,
7114
+ menuItems: Array,
7115
+ depth: { type: Number, optional: true },
7116
+ maxHeight: { type: Number, optional: true },
7117
+ onClose: Function,
7118
+ onMenuClicked: { type: Function, optional: true },
7119
+ menuId: { type: String, optional: true },
7120
+ };
7032
7121
  static components = { Menu, Popover };
7033
7122
  static defaultProps = {
7034
7123
  depth: 1,
@@ -7185,15 +7274,6 @@ class Menu extends Component {
7185
7274
  }
7186
7275
  }
7187
7276
  }
7188
- Menu.props = {
7189
- position: Object,
7190
- menuItems: Array,
7191
- depth: { type: Number, optional: true },
7192
- maxHeight: { type: Number, optional: true },
7193
- onClose: Function,
7194
- onMenuClicked: { type: Function, optional: true },
7195
- menuId: { type: String, optional: true },
7196
- };
7197
7277
 
7198
7278
  const LINK_TOOLTIP_HEIGHT = 32;
7199
7279
  const LINK_TOOLTIP_WIDTH = 220;
@@ -7246,8 +7326,12 @@ css /* scss */ `
7246
7326
  }
7247
7327
  `;
7248
7328
  class LinkDisplay extends Component {
7249
- static components = { Menu };
7250
7329
  static template = "o-spreadsheet-LinkDisplay";
7330
+ static props = {
7331
+ cellPosition: Object,
7332
+ onClosed: { type: Function, optional: true },
7333
+ };
7334
+ static components = { Menu };
7251
7335
  get cell() {
7252
7336
  const { col, row } = this.props.cellPosition;
7253
7337
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -7302,10 +7386,6 @@ const LinkCellPopoverBuilder = {
7302
7386
  };
7303
7387
  },
7304
7388
  };
7305
- LinkDisplay.props = {
7306
- cellPosition: Object,
7307
- onClosed: { type: Function, optional: true },
7308
- };
7309
7389
 
7310
7390
  /**
7311
7391
  * Tokenizer
@@ -7939,6 +8019,10 @@ css /* scss */ `
7939
8019
  `;
7940
8020
  class LinkEditor extends Component {
7941
8021
  static template = "o-spreadsheet-LinkEditor";
8022
+ static props = {
8023
+ cellPosition: Object,
8024
+ onClosed: { type: Function, optional: true },
8025
+ };
7942
8026
  static components = { Menu };
7943
8027
  menuItems = linkMenuRegistry.getMenuItems();
7944
8028
  link = useState(this.defaultState);
@@ -8036,10 +8120,6 @@ const LinkEditorPopoverBuilder = {
8036
8120
  };
8037
8121
  },
8038
8122
  };
8039
- LinkEditor.props = {
8040
- cellPosition: Object,
8041
- onClosed: { type: Function, optional: true },
8042
- };
8043
8123
 
8044
8124
  const cellPopoverRegistry = new Registry();
8045
8125
  cellPopoverRegistry
@@ -8322,6 +8402,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale })
8322
8402
  labels: labels.map(truncateLabel),
8323
8403
  datasets: [],
8324
8404
  },
8405
+ platform: undefined,
8325
8406
  plugins: [],
8326
8407
  };
8327
8408
  }
@@ -8901,7 +8982,7 @@ function createGaugeChartRuntime(chart, getters) {
8901
8982
  });
8902
8983
  return {
8903
8984
  chartJsConfig: config,
8904
- background: getters.getBackgroundOfSingleCellChart(chart.background, dataRange),
8985
+ background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
8905
8986
  };
8906
8987
  }
8907
8988
 
@@ -8982,7 +9063,7 @@ function getFormatMinDisplayUnit(format) {
8982
9063
  else if (format.includes("h") || format.includes("H")) {
8983
9064
  return "hour";
8984
9065
  }
8985
- else if (format.includes("D")) {
9066
+ else if (format.includes("d")) {
8986
9067
  return "day";
8987
9068
  }
8988
9069
  else if (format.includes("M")) {
@@ -9494,6 +9575,27 @@ function calculatePercentage(dataset, dataIndex) {
9494
9575
  const percentage = (dataset[dataIndex] / total) * 100;
9495
9576
  return percentage.toFixed(2);
9496
9577
  }
9578
+ function filterNegativeValues(labels, datasets) {
9579
+ const dataPointsIndexes = labels.reduce((indexes, label, i) => {
9580
+ const shouldKeep = datasets.some((dataset) => {
9581
+ const dataPoint = dataset.data[i];
9582
+ return typeof dataPoint !== "number" || dataPoint >= 0;
9583
+ });
9584
+ if (shouldKeep) {
9585
+ indexes.push(i);
9586
+ }
9587
+ return indexes;
9588
+ }, []);
9589
+ const filteredLabels = dataPointsIndexes.map((i) => labels[i] || "");
9590
+ const filteredDatasets = datasets.map((dataset) => ({
9591
+ ...dataset,
9592
+ data: dataPointsIndexes.map((i) => {
9593
+ const dataPoint = dataset.data[i];
9594
+ return typeof dataPoint !== "number" || dataPoint >= 0 ? dataPoint : 0;
9595
+ }),
9596
+ }));
9597
+ return { labels: filteredLabels, dataSetsValues: filteredDatasets };
9598
+ }
9497
9599
  function createPieChartRuntime(chart, getters) {
9498
9600
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
9499
9601
  let labels = labelValues.formattedValues;
@@ -9507,6 +9609,7 @@ function createPieChartRuntime(chart, getters) {
9507
9609
  if (chart.aggregated) {
9508
9610
  ({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
9509
9611
  }
9612
+ ({ dataSetsValues, labels } = filterNegativeValues(labels, dataSetsValues));
9510
9613
  const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
9511
9614
  const locale = getters.getLocale();
9512
9615
  const config = getPieConfiguration(chart, labels, { format: dataSetFormat, locale });
@@ -9604,6 +9707,10 @@ css /* scss */ `
9604
9707
  `;
9605
9708
  class ChartFigure extends Component {
9606
9709
  static template = "o-spreadsheet-ChartFigure";
9710
+ static props = {
9711
+ figure: Object,
9712
+ onFigureDeleted: Function,
9713
+ };
9607
9714
  static components = {};
9608
9715
  onDoubleClick() {
9609
9716
  this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
@@ -9621,13 +9728,13 @@ class ChartFigure extends Component {
9621
9728
  return component;
9622
9729
  }
9623
9730
  }
9624
- ChartFigure.props = {
9625
- figure: Object,
9626
- onFigureDeleted: Function,
9627
- };
9628
9731
 
9629
9732
  class ImageFigure extends Component {
9630
9733
  static template = "o-spreadsheet-ImageFigure";
9734
+ static props = {
9735
+ figure: Object,
9736
+ onFigureDeleted: Function,
9737
+ };
9631
9738
  static components = {};
9632
9739
  // ---------------------------------------------------------------------------
9633
9740
  // Getters
@@ -9639,10 +9746,6 @@ class ImageFigure extends Component {
9639
9746
  return this.env.model.getters.getImagePath(this.figureId);
9640
9747
  }
9641
9748
  }
9642
- ImageFigure.props = {
9643
- figure: Object,
9644
- onFigureDeleted: Function,
9645
- };
9646
9749
 
9647
9750
  function centerFigurePosition(getters, size) {
9648
9751
  const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
@@ -10344,7 +10447,7 @@ function setStyle(env, style) {
10344
10447
  // Simple actions
10345
10448
  //------------------------------------------------------------------------------
10346
10449
  const PASTE_ACTION = async (env) => paste$1(env);
10347
- const PASTE_VALUE_ACTION = async (env) => paste$1(env, "onlyValue");
10450
+ const PASTE_AS_VALUE_ACTION = async (env) => paste$1(env, "asValue");
10348
10451
  async function paste$1(env, pasteOption) {
10349
10452
  const spreadsheetClipboard = env.model.getters.getClipboardTextContent();
10350
10453
  const osClipboard = await env.clipboard.readText();
@@ -10357,7 +10460,7 @@ async function paste$1(env, pasteOption) {
10357
10460
  else {
10358
10461
  interactivePaste(env, target, pasteOption);
10359
10462
  }
10360
- if (env.model.getters.isCutOperation() && pasteOption !== "onlyValue") {
10463
+ if (env.model.getters.isCutOperation() && pasteOption !== "asValue") {
10361
10464
  await env.clipboard.write({ [ClipboardMIMEType.PlainText]: "" });
10362
10465
  }
10363
10466
  break;
@@ -10772,9 +10875,9 @@ const pasteSpecial = {
10772
10875
  icon: "o-spreadsheet-Icon.PASTE",
10773
10876
  };
10774
10877
  const pasteSpecialValue = {
10775
- name: _t("Paste value only"),
10878
+ name: _t("Paste as value"),
10776
10879
  description: "Ctrl+Shift+V",
10777
- execute: PASTE_VALUE_ACTION,
10880
+ execute: PASTE_AS_VALUE_ACTION,
10778
10881
  };
10779
10882
  const pasteSpecialFormat = {
10780
10883
  name: _t("Paste format only"),
@@ -10930,6 +11033,9 @@ function arg(definition, description = "") {
10930
11033
  function makeArg(str, description) {
10931
11034
  let parts = str.match(ARG_REGEXP);
10932
11035
  let name = parts[1].trim();
11036
+ if (!name) {
11037
+ throw new Error(`Function argument definition is missing a name: '${str}'.`);
11038
+ }
10933
11039
  let types = [];
10934
11040
  let isOptional = false;
10935
11041
  let isRepeating = false;
@@ -14652,7 +14758,7 @@ const DATE = {
14652
14758
  if (_year < 1900) {
14653
14759
  _year += 1900;
14654
14760
  }
14655
- const jsDate = new Date(_year, _month - 1, _day);
14761
+ const jsDate = new DateTime(_year, _month - 1, _day);
14656
14762
  const result = jsDateToRoundNumber(jsDate);
14657
14763
  assert(() => result >= 0, _t("The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900."));
14658
14764
  return result;
@@ -14695,7 +14801,7 @@ const DATEDIF = {
14695
14801
  // See: https://support.microsoft.com/en-us/office/datedif-function-25dba1a4-2812-480b-84dd-8b32a451b35c
14696
14802
  let days = jsEndDate.getDate() - jsStartDate.getDate();
14697
14803
  if (days < 0) {
14698
- const monthBeforeEndMonth = new Date(jsEndDate.getFullYear(), jsEndDate.getMonth() - 1, 1);
14804
+ const monthBeforeEndMonth = new DateTime(jsEndDate.getFullYear(), jsEndDate.getMonth() - 1, 1);
14699
14805
  const daysInMonthBeforeEndMonth = getDaysInMonth(monthBeforeEndMonth);
14700
14806
  days = daysInMonthBeforeEndMonth - Math.abs(days);
14701
14807
  }
@@ -14704,7 +14810,7 @@ const DATEDIF = {
14704
14810
  if (areTwoDatesWithinOneYear(_startDate, _endDate)) {
14705
14811
  return getTimeDifferenceInWholeDays(jsStartDate, jsEndDate);
14706
14812
  }
14707
- const endDateWithinOneYear = new Date(jsStartDate.getFullYear(), jsEndDate.getMonth(), jsEndDate.getDate());
14813
+ const endDateWithinOneYear = new DateTime(jsStartDate.getFullYear(), jsEndDate.getMonth(), jsEndDate.getDate());
14708
14814
  let days = getTimeDifferenceInWholeDays(jsStartDate, endDateWithinOneYear);
14709
14815
  if (days < 0) {
14710
14816
  endDateWithinOneYear.setFullYear(jsStartDate.getFullYear() + 1);
@@ -14821,7 +14927,7 @@ const EOMONTH = {
14821
14927
  const _months = Math.trunc(toNumber(months, this.locale));
14822
14928
  const yStart = _startDate.getFullYear();
14823
14929
  const mStart = _startDate.getMonth();
14824
- const jsDate = new Date(yStart, mStart + _months + 1, 0);
14930
+ const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
14825
14931
  return jsDateToRoundNumber(jsDate);
14826
14932
  },
14827
14933
  isExported: true,
@@ -14858,17 +14964,17 @@ const ISOWEEKNUM = {
14858
14964
  // The first week of the year is the week that contains the first
14859
14965
  // Thursday of the year.
14860
14966
  let firstThursday = 1;
14861
- while (new Date(y, 0, firstThursday).getDay() !== 4) {
14967
+ while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
14862
14968
  firstThursday += 1;
14863
14969
  }
14864
- const firstDayOfFirstWeek = new Date(y, 0, firstThursday - 3);
14970
+ const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
14865
14971
  // The last week of the year is the week that contains the last Thursday of
14866
14972
  // the year.
14867
14973
  let lastThursday = 31;
14868
- while (new Date(y, 11, lastThursday).getDay() !== 4) {
14974
+ while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
14869
14975
  lastThursday -= 1;
14870
14976
  }
14871
- const lastDayOfLastWeek = new Date(y, 11, lastThursday + 3);
14977
+ const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
14872
14978
  // B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
14873
14979
  // If our date < firstDayOfFirstWeek then it's in the weeks of the year before
14874
14980
  let offsetYear;
@@ -14894,17 +15000,17 @@ const ISOWEEKNUM = {
14894
15000
  case 1:
14895
15001
  // firstDay is the 1st day of the 1st week of the year after
14896
15002
  // firstDay = lastDayOfLastWeek + 1 Day
14897
- firstDay = new Date(y, 11, lastThursday + 3 + 1);
15003
+ firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
14898
15004
  break;
14899
15005
  case -1:
14900
15006
  // firstDay is the 1st day of the 1st week of the previous year.
14901
15007
  // The first week of the previous year is the week that contains the
14902
15008
  // first Thursday of the previous year.
14903
15009
  let firstThursdayPreviousYear = 1;
14904
- while (new Date(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
15010
+ while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
14905
15011
  firstThursdayPreviousYear += 1;
14906
15012
  }
14907
- firstDay = new Date(y - 1, 0, firstThursdayPreviousYear - 3);
15013
+ firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
14908
15014
  break;
14909
15015
  }
14910
15016
  const diff = (_date.getTime() - firstDay.getTime()) / MS_PER_DAY;
@@ -15039,8 +15145,8 @@ const NETWORKDAYS_INTL = {
15039
15145
  });
15040
15146
  }
15041
15147
  const invertDate = _startDate.getTime() > _endDate.getTime();
15042
- const stopDate = new Date((invertDate ? _startDate : _endDate).getTime());
15043
- let stepDate = new Date((invertDate ? _endDate : _startDate).getTime());
15148
+ const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
15149
+ let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
15044
15150
  const timeStopDate = stopDate.getTime();
15045
15151
  let timeStepDate = stepDate.getTime();
15046
15152
  let netWorkingDay = 0;
@@ -15066,8 +15172,7 @@ const NOW = {
15066
15172
  return getDateTimeFormat(this.locale);
15067
15173
  },
15068
15174
  compute: function () {
15069
- let today = new Date();
15070
- today.setMilliseconds(0);
15175
+ let today = DateTime.now();
15071
15176
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
15072
15177
  const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
15073
15178
  return Math.floor(delta / MS_PER_DAY) + time;
@@ -15141,8 +15246,8 @@ const TODAY = {
15141
15246
  return this.locale.dateFormat;
15142
15247
  },
15143
15248
  compute: function () {
15144
- const today = new Date();
15145
- const jsDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
15249
+ const today = DateTime.now();
15250
+ const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
15146
15251
  return jsDateToRoundNumber(jsDate);
15147
15252
  },
15148
15253
  isExported: true,
@@ -15197,10 +15302,10 @@ const WEEKNUM = {
15197
15302
  }
15198
15303
  const y = _date.getFullYear();
15199
15304
  let dayStart = 1;
15200
- let startDayOfFirstWeek = new Date(y, 0, dayStart);
15305
+ let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
15201
15306
  while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
15202
15307
  dayStart += 1;
15203
- startDayOfFirstWeek = new Date(y, 0, dayStart);
15308
+ startDayOfFirstWeek = new DateTime(y, 0, dayStart);
15204
15309
  }
15205
15310
  const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / MS_PER_DAY;
15206
15311
  if (dif < 0) {
@@ -15258,7 +15363,7 @@ const WORKDAY_INTL = {
15258
15363
  timesHoliday.add(holiday.getTime());
15259
15364
  });
15260
15365
  }
15261
- let stepDate = new Date(_startDate.getTime());
15366
+ let stepDate = DateTime.fromTimestamp(_startDate.getTime());
15262
15367
  let timeStepDate = stepDate.getTime();
15263
15368
  const unitDay = Math.sign(_numDays);
15264
15369
  let stepDay = Math.abs(_numDays);
@@ -15322,7 +15427,7 @@ const MONTH_START = {
15322
15427
  const _startDate = toJsDate(date, this.locale);
15323
15428
  const yStart = _startDate.getFullYear();
15324
15429
  const mStart = _startDate.getMonth();
15325
- const jsDate = new Date(yStart, mStart, 1);
15430
+ const jsDate = new DateTime(yStart, mStart, 1);
15326
15431
  return jsDateToRoundNumber(jsDate);
15327
15432
  },
15328
15433
  };
@@ -15364,7 +15469,7 @@ const QUARTER_START = {
15364
15469
  compute: function (date) {
15365
15470
  const quarter = QUARTER.compute.bind(this)(date);
15366
15471
  const year = YEAR.compute.bind(this)(date);
15367
- const jsDate = new Date(year, (quarter - 1) * 3, 1);
15472
+ const jsDate = new DateTime(year, (quarter - 1) * 3, 1);
15368
15473
  return jsDateToRoundNumber(jsDate);
15369
15474
  },
15370
15475
  };
@@ -15381,7 +15486,7 @@ const QUARTER_END = {
15381
15486
  compute: function (date) {
15382
15487
  const quarter = QUARTER.compute.bind(this)(date);
15383
15488
  const year = YEAR.compute.bind(this)(date);
15384
- const jsDate = new Date(year, quarter * 3, 0);
15489
+ const jsDate = new DateTime(year, quarter * 3, 0);
15385
15490
  return jsDateToRoundNumber(jsDate);
15386
15491
  },
15387
15492
  };
@@ -15397,7 +15502,7 @@ const YEAR_START = {
15397
15502
  },
15398
15503
  compute: function (date) {
15399
15504
  const year = YEAR.compute.bind(this)(date);
15400
- const jsDate = new Date(year, 0, 1);
15505
+ const jsDate = new DateTime(year, 0, 1);
15401
15506
  return jsDateToRoundNumber(jsDate);
15402
15507
  },
15403
15508
  };
@@ -15413,7 +15518,7 @@ const YEAR_END = {
15413
15518
  },
15414
15519
  compute: function (date) {
15415
15520
  const year = YEAR.compute.bind(this)(date);
15416
- const jsDate = new Date(year + 1, 0, 0);
15521
+ const jsDate = new DateTime(year + 1, 0, 0);
15417
15522
  return jsDateToRoundNumber(jsDate);
15418
15523
  },
15419
15524
  };
@@ -15461,8 +15566,8 @@ const DEFAULT_DELTA_ARG = 0;
15461
15566
  const DELTA = {
15462
15567
  description: _t("Compare two numeric values, returning 1 if they're equal."),
15463
15568
  args: [
15464
- arg(" (number)", _t("The first number to compare.")),
15465
- arg(` (number, default=${DEFAULT_DELTA_ARG})`, _t("The second number to compare.")),
15569
+ arg("number1 (number)", _t("The first number to compare.")),
15570
+ arg(`number2 (number, default=${DEFAULT_DELTA_ARG})`, _t("The second number to compare.")),
15466
15571
  ],
15467
15572
  returns: ["NUMBER"],
15468
15573
  compute: function (number1, number2 = DEFAULT_DELTA_ARG) {
@@ -15889,7 +15994,7 @@ function assertDeprecationFactorStrictlyPositive(factor) {
15889
15994
  function assertSettlementLessThanOneYearBeforeMaturity(settlement, maturity, locale) {
15890
15995
  const startDate = toJsDate(settlement, locale);
15891
15996
  const endDate = toJsDate(maturity, locale);
15892
- const startDatePlusOneYear = new Date(startDate);
15997
+ const startDatePlusOneYear = toJsDate(settlement, locale);
15893
15998
  startDatePlusOneYear.setFullYear(startDate.getFullYear() + 1);
15894
15999
  assert(() => endDate.getTime() <= startDatePlusOneYear.getTime(), _t("The settlement date (%s) must at most one year after the maturity date (%s).", settlement.toString(), maturity.toString()));
15895
16000
  }
@@ -16024,7 +16129,7 @@ const AMORLINC = {
16024
16129
  arg("salvage (number)", _t("The value of the asset at the end of depreciation.")),
16025
16130
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16026
16131
  arg("rate (number)", _t("The deprecation rate.")),
16027
- arg(" (number, optional)", _t("An indicator of what day count method to use.")),
16132
+ arg("day_count_convention (number, optional)", _t("An indicator of what day count method to use.")),
16028
16133
  ],
16029
16134
  returns: ["NUMBER"],
16030
16135
  compute: function (cost, purchaseDate, firstPeriodEnd, salvage, period, rate, dayCountConvention = DEFAULT_DAY_COUNT_CONVENTION) {
@@ -19196,8 +19301,8 @@ const MID = {
19196
19301
  description: _t("A segment of a string."),
19197
19302
  args: [
19198
19303
  arg("text (string)", _t("The string to extract a segment from.")),
19199
- arg(" (number)", _t("The index from the left of string from which to begin extracting. The first character in string has the index 1.")),
19200
- arg(" (number)", _t("The length of the segment to extract.")),
19304
+ arg("starting_at (number)", _t("The index from the left of string from which to begin extracting. The first character in string has the index 1.")),
19305
+ arg("extract_length (number)", _t("The length of the segment to extract.")),
19201
19306
  ],
19202
19307
  returns: ["STRING"],
19203
19308
  compute: function (text, starting_at, extract_length) {
@@ -20013,6 +20118,11 @@ const formatNumberAutomatic = {
20013
20118
  execute: (env) => setFormatter(env, ""),
20014
20119
  isActive: (env) => isAutomaticFormatSelected(env),
20015
20120
  };
20121
+ const formatNumberPlainText = {
20122
+ name: _t("Plain text"),
20123
+ execute: (env) => setFormatter(env, PLAIN_TEXT_FORMAT),
20124
+ isActive: (env) => isFormatSelected(env, PLAIN_TEXT_FORMAT),
20125
+ };
20016
20126
  const formatNumberNumber = createFormatActionSpec({
20017
20127
  name: _t("Number"),
20018
20128
  descriptionValue: 1000.12,
@@ -20372,6 +20482,7 @@ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
20372
20482
  formatNumberFullWeekDayAndMonth: formatNumberFullWeekDayAndMonth,
20373
20483
  formatNumberNumber: formatNumberNumber,
20374
20484
  formatNumberPercent: formatNumberPercent,
20485
+ formatNumberPlainText: formatNumberPlainText,
20375
20486
  formatNumberShortMonth: formatNumberShortMonth,
20376
20487
  formatNumberShortWeekDay: formatNumberShortWeekDay,
20377
20488
  formatNumberTime: formatNumberTime,
@@ -20802,6 +20913,10 @@ numberFormatMenuRegistry
20802
20913
  .add("format_number_automatic", {
20803
20914
  ...formatNumberAutomatic,
20804
20915
  sequence: 10,
20916
+ })
20917
+ .add("format_number_plain_text", {
20918
+ ...formatNumberPlainText,
20919
+ sequence: 15,
20805
20920
  separator: true,
20806
20921
  })
20807
20922
  .add("format_number_number", {
@@ -21400,10 +21515,10 @@ const arrowMap = {
21400
21515
  function updateSelectionWithArrowKeys(ev, selection) {
21401
21516
  const direction = arrowMap[ev.key];
21402
21517
  if (ev.shiftKey) {
21403
- selection.resizeAnchorZone(direction, ev.ctrlKey ? "end" : 1);
21518
+ selection.resizeAnchorZone(direction, isCtrlKey(ev) ? "end" : 1);
21404
21519
  }
21405
21520
  else {
21406
- selection.moveAnchorCell(direction, ev.ctrlKey ? "end" : 1);
21521
+ selection.moveAnchorCell(direction, isCtrlKey(ev) ? "end" : 1);
21407
21522
  }
21408
21523
  }
21409
21524
 
@@ -21470,6 +21585,15 @@ css /* scss */ `
21470
21585
  */
21471
21586
  class SelectionInput extends Component {
21472
21587
  static template = "o-spreadsheet-SelectionInput";
21588
+ static props = {
21589
+ ranges: Function,
21590
+ hasSingleRange: { type: Boolean, optional: true },
21591
+ required: { type: Boolean, optional: true },
21592
+ isInvalid: { type: Boolean, optional: true },
21593
+ class: { type: String, optional: true },
21594
+ onSelectionChanged: { type: Function, optional: true },
21595
+ onSelectionConfirmed: { type: Function, optional: true },
21596
+ };
21473
21597
  id = uuidGenerator$1.uuidv4();
21474
21598
  previousRanges = this.props.ranges() || [];
21475
21599
  originSheet = this.env.model.getters.getActiveSheetId();
@@ -21632,15 +21756,6 @@ class SelectionInput extends Component {
21632
21756
  this.env.model.dispatch("UNFOCUS_SELECTION_INPUT");
21633
21757
  }
21634
21758
  }
21635
- SelectionInput.props = {
21636
- ranges: Function,
21637
- hasSingleRange: { type: Boolean, optional: true },
21638
- required: { type: Boolean, optional: true },
21639
- isInvalid: { type: Boolean, optional: true },
21640
- class: { type: String, optional: true },
21641
- onSelectionChanged: { type: Function, optional: true },
21642
- onSelectionConfirmed: { type: Function, optional: true },
21643
- };
21644
21759
 
21645
21760
  css /* scss */ `
21646
21761
  .o-validation-error,
@@ -21656,6 +21771,10 @@ css /* scss */ `
21656
21771
  `;
21657
21772
  class ValidationMessages extends Component {
21658
21773
  static template = "o-spreadsheet-ValidationMessages";
21774
+ static props = {
21775
+ messages: Array,
21776
+ msgType: String,
21777
+ };
21659
21778
  get divClasses() {
21660
21779
  if (this.props.msgType === "warning") {
21661
21780
  return "o-validation-warning text-warning";
@@ -21663,14 +21782,96 @@ class ValidationMessages extends Component {
21663
21782
  return "o-validation-error text-danger";
21664
21783
  }
21665
21784
  }
21666
- ValidationMessages.props = {
21667
- messages: Array,
21668
- msgType: String,
21669
- };
21785
+
21786
+ css /* scss */ `
21787
+ .o-checkbox {
21788
+ display: flex;
21789
+ justify-items: center;
21790
+ input {
21791
+ margin-right: 5px;
21792
+ }
21793
+ }
21794
+ `;
21795
+ class Checkbox extends Component {
21796
+ static template = "o-spreadsheet.Checkbox";
21797
+ static props = {
21798
+ label: { type: String, optional: true },
21799
+ value: { type: Boolean, optional: true },
21800
+ className: { type: String, optional: true },
21801
+ name: { type: String, optional: true },
21802
+ onChange: Function,
21803
+ };
21804
+ static defaultProps = { value: false };
21805
+ onChange(ev) {
21806
+ const value = ev.target.checked;
21807
+ this.props.onChange(value);
21808
+ }
21809
+ }
21810
+
21811
+ class Section extends Component {
21812
+ static template = "o_spreadsheet.Section";
21813
+ static props = {
21814
+ class: { type: String, optional: true },
21815
+ slots: Object,
21816
+ };
21817
+ }
21818
+
21819
+ class ChartDataSeries extends Component {
21820
+ static template = "o-spreadsheet.ChartDataSeries";
21821
+ static components = { SelectionInput, Section };
21822
+ static props = {
21823
+ ranges: Function,
21824
+ hasSingleRange: { type: Boolean, optional: true },
21825
+ onSelectionChanged: Function,
21826
+ onSelectionConfirmed: Function,
21827
+ };
21828
+ get title() {
21829
+ return this.props.hasSingleRange ? _t("Data range") : _t("Data series");
21830
+ }
21831
+ }
21832
+
21833
+ class ChartErrorSection extends Component {
21834
+ static template = "o-spreadsheet.ChartErrorSection";
21835
+ static components = { Section, ValidationMessages };
21836
+ static props = { messages: { type: Array, element: String } };
21837
+ }
21838
+
21839
+ class ChartLabelRange extends Component {
21840
+ static template = "o-spreadsheet.ChartLabelRange";
21841
+ static components = { SelectionInput, Checkbox, Section };
21842
+ static props = {
21843
+ title: { type: String, optional: true },
21844
+ range: Function,
21845
+ isInvalid: Boolean,
21846
+ required: { type: Boolean, optional: true },
21847
+ onSelectionChanged: Function,
21848
+ onSelectionConfirmed: Function,
21849
+ options: { type: Array, optional: true },
21850
+ };
21851
+ static defaultProps = {
21852
+ title: _t("Categories / Labels"),
21853
+ options: [],
21854
+ required: false,
21855
+ };
21856
+ }
21670
21857
 
21671
21858
  class LineBarPieConfigPanel extends Component {
21672
21859
  static template = "o-spreadsheet-LineBarPieConfigPanel";
21673
- static components = { SelectionInput, ValidationMessages };
21860
+ static components = {
21861
+ SelectionInput,
21862
+ ValidationMessages,
21863
+ ChartDataSeries,
21864
+ ChartLabelRange,
21865
+ Section,
21866
+ Checkbox,
21867
+ ChartErrorSection,
21868
+ };
21869
+ static props = {
21870
+ figureId: String,
21871
+ definition: Object,
21872
+ updateChart: Function,
21873
+ canUpdateChart: Function,
21874
+ };
21674
21875
  state = useState({
21675
21876
  datasetDispatchResult: undefined,
21676
21877
  labelsDispatchResult: undefined,
@@ -21694,9 +21895,22 @@ class LineBarPieConfigPanel extends Component {
21694
21895
  get isLabelInvalid() {
21695
21896
  return !!this.state.labelsDispatchResult?.isCancelledBecause("InvalidLabelRange" /* CommandResult.InvalidLabelRange */);
21696
21897
  }
21697
- onUpdateDataSetsHaveTitle(ev) {
21898
+ get dataSetsHaveTitleLabel() {
21899
+ return _t("Use row %s as headers", this.calculateHeaderPosition() || "");
21900
+ }
21901
+ getLabelRangeOptions() {
21902
+ return [
21903
+ {
21904
+ name: "aggregated",
21905
+ label: _t("Aggregate"),
21906
+ value: this.props.definition.aggregated,
21907
+ onChange: this.onUpdateAggregated.bind(this),
21908
+ },
21909
+ ];
21910
+ }
21911
+ onUpdateDataSetsHaveTitle(dataSetsHaveTitle) {
21698
21912
  this.props.updateChart(this.props.figureId, {
21699
- dataSetsHaveTitle: ev.target.checked,
21913
+ dataSetsHaveTitle,
21700
21914
  });
21701
21915
  }
21702
21916
  /**
@@ -21736,9 +21950,9 @@ class LineBarPieConfigPanel extends Component {
21736
21950
  getLabelRange() {
21737
21951
  return this.labelRange || "";
21738
21952
  }
21739
- onUpdateAggregated(ev) {
21953
+ onUpdateAggregated(aggregated) {
21740
21954
  this.props.updateChart(this.props.figureId, {
21741
- aggregated: ev.target.checked,
21955
+ aggregated,
21742
21956
  });
21743
21957
  }
21744
21958
  calculateHeaderPosition() {
@@ -21758,23 +21972,20 @@ class LineBarPieConfigPanel extends Component {
21758
21972
  return undefined;
21759
21973
  }
21760
21974
  }
21761
- LineBarPieConfigPanel.props = {
21762
- figureId: String,
21763
- definition: Object,
21764
- updateChart: Function,
21765
- canUpdateChart: Function,
21766
- };
21767
21975
 
21768
21976
  class BarConfigPanel extends LineBarPieConfigPanel {
21769
21977
  static template = "o-spreadsheet-BarConfigPanel";
21770
- onUpdateStacked(ev) {
21978
+ get stackedLabel() {
21979
+ return _t("Stacked barchart");
21980
+ }
21981
+ onUpdateStacked(stacked) {
21771
21982
  this.props.updateChart(this.props.figureId, {
21772
- stacked: ev.target.checked,
21983
+ stacked,
21773
21984
  });
21774
21985
  }
21775
- onUpdateAggregated(ev) {
21986
+ onUpdateAggregated(aggregated) {
21776
21987
  this.props.updateChart(this.props.figureId, {
21777
- aggregated: ev.target.checked,
21988
+ aggregated,
21778
21989
  });
21779
21990
  }
21780
21991
  }
@@ -22102,6 +22313,12 @@ css /* scss */ `
22102
22313
  `;
22103
22314
  class ColorPicker extends Component {
22104
22315
  static template = "o-spreadsheet-ColorPicker";
22316
+ static props = {
22317
+ onColorPicked: Function,
22318
+ currentColor: { type: String, optional: true },
22319
+ maxHeight: { type: Number, optional: true },
22320
+ anchorRect: Object,
22321
+ };
22105
22322
  static defaultProps = { currentColor: "" };
22106
22323
  static components = { Popover };
22107
22324
  COLORS = COLOR_PICKER_DEFAULTS;
@@ -22237,12 +22454,6 @@ class ColorPicker extends Component {
22237
22454
  return isSameColor(color1, color2);
22238
22455
  }
22239
22456
  }
22240
- ColorPicker.props = {
22241
- onColorPicked: Function,
22242
- currentColor: { type: String, optional: true },
22243
- maxHeight: { type: Number, optional: true },
22244
- anchorRect: Object,
22245
- };
22246
22457
 
22247
22458
  css /* scss */ `
22248
22459
  .o-color-picker-widget {
@@ -22280,6 +22491,17 @@ css /* scss */ `
22280
22491
  `;
22281
22492
  class ColorPickerWidget extends Component {
22282
22493
  static template = "o-spreadsheet-ColorPickerWidget";
22494
+ static props = {
22495
+ currentColor: { type: String, optional: true },
22496
+ toggleColorPicker: Function,
22497
+ showColorPicker: Boolean,
22498
+ onColorPicked: Function,
22499
+ icon: String,
22500
+ title: { type: String, optional: true },
22501
+ disabled: { type: Boolean, optional: true },
22502
+ dropdownMaxHeight: { type: Number, optional: true },
22503
+ class: { type: String, optional: true },
22504
+ };
22283
22505
  static components = { ColorPicker };
22284
22506
  colorPickerButtonRef = useRef("colorPickerButton");
22285
22507
  get iconStyle() {
@@ -22298,44 +22520,55 @@ class ColorPickerWidget extends Component {
22298
22520
  };
22299
22521
  }
22300
22522
  }
22301
- ColorPickerWidget.props = {
22302
- currentColor: { type: String, optional: true },
22303
- toggleColorPicker: Function,
22304
- showColorPicker: Boolean,
22305
- onColorPicked: Function,
22306
- icon: String,
22307
- title: { type: String, optional: true },
22308
- disabled: { type: Boolean, optional: true },
22309
- dropdownMaxHeight: { type: Number, optional: true },
22310
- class: { type: String, optional: true },
22311
- };
22312
22523
 
22313
- class LineBarPieDesignPanel extends Component {
22314
- static template = "o-spreadsheet-LineBarPieDesignPanel";
22315
- static components = { ColorPickerWidget };
22316
- state = useState({
22317
- title: "",
22318
- fillColorTool: false,
22319
- });
22320
- onClick(ev) {
22321
- this.state.fillColorTool = false;
22322
- }
22524
+ class ChartColor extends Component {
22525
+ static template = "o-spreadsheet.ChartColor";
22526
+ static components = { ColorPickerWidget, Section };
22527
+ static props = {
22528
+ currentColor: { type: String, optional: true },
22529
+ onColorPicked: Function,
22530
+ };
22531
+ state;
22323
22532
  setup() {
22324
- this.state.title = _t(this.props.definition.title);
22325
- useExternalListener(window, "click", this.onClick);
22533
+ this.state = useState({ pickerOpened: false });
22534
+ useExternalListener(window, "click", this.closePicker);
22326
22535
  }
22327
- toggleColorPicker() {
22328
- this.state.fillColorTool = !this.state.fillColorTool;
22536
+ closePicker() {
22537
+ this.state.pickerOpened = false;
22538
+ }
22539
+ togglePicker() {
22540
+ this.state.pickerOpened = !this.state.pickerOpened;
22541
+ }
22542
+ }
22543
+
22544
+ class ChartTitle extends Component {
22545
+ static template = "o-spreadsheet.ChartTitle";
22546
+ static components = { ColorPickerWidget, Section };
22547
+ static props = { title: String, update: Function };
22548
+ updateTitle(ev) {
22549
+ this.props.update(ev.target.value);
22550
+ }
22551
+ }
22552
+
22553
+ class LineBarPieDesignPanel extends Component {
22554
+ static template = "o-spreadsheet-LineBarPieDesignPanel";
22555
+ static components = { ChartColor, ColorPickerWidget, ChartTitle, Section };
22556
+ static props = {
22557
+ figureId: String,
22558
+ definition: Object,
22559
+ updateChart: Function,
22560
+ canUpdateChart: Function,
22561
+ };
22562
+ get title() {
22563
+ return _t(this.props.definition.title);
22329
22564
  }
22330
22565
  updateBackgroundColor(color) {
22331
22566
  this.props.updateChart(this.props.figureId, {
22332
22567
  background: color,
22333
22568
  });
22334
22569
  }
22335
- updateTitle() {
22336
- this.props.updateChart(this.props.figureId, {
22337
- title: this.state.title,
22338
- });
22570
+ updateTitle(title) {
22571
+ this.props.updateChart(this.props.figureId, { title });
22339
22572
  }
22340
22573
  updateSelect(attr, ev) {
22341
22574
  this.props.updateChart(this.props.figureId, {
@@ -22343,12 +22576,6 @@ class LineBarPieDesignPanel extends Component {
22343
22576
  });
22344
22577
  }
22345
22578
  }
22346
- LineBarPieDesignPanel.props = {
22347
- figureId: String,
22348
- definition: Object,
22349
- updateChart: Function,
22350
- canUpdateChart: Function,
22351
- };
22352
22579
 
22353
22580
  class BarChartDesignPanel extends LineBarPieDesignPanel {
22354
22581
  static template = "o-spreadsheet-BarChartDesignPanel";
@@ -22356,7 +22583,13 @@ class BarChartDesignPanel extends LineBarPieDesignPanel {
22356
22583
 
22357
22584
  class GaugeChartConfigPanel extends Component {
22358
22585
  static template = "o-spreadsheet-GaugeChartConfigPanel";
22359
- static components = { SelectionInput, ValidationMessages };
22586
+ static components = { SelectionInput, ChartErrorSection, ChartDataSeries };
22587
+ static props = {
22588
+ figureId: String,
22589
+ definition: Object,
22590
+ updateChart: Function,
22591
+ canUpdateChart: Function,
22592
+ };
22360
22593
  state = useState({
22361
22594
  dataRangeDispatchResult: undefined,
22362
22595
  });
@@ -22383,12 +22616,6 @@ class GaugeChartConfigPanel extends Component {
22383
22616
  return this.dataRange || "";
22384
22617
  }
22385
22618
  }
22386
- GaugeChartConfigPanel.props = {
22387
- figureId: String,
22388
- definition: Object,
22389
- updateChart: Function,
22390
- canUpdateChart: Function,
22391
- };
22392
22619
 
22393
22620
  css /* scss */ `
22394
22621
  .o-gauge-color-set {
@@ -22423,31 +22650,35 @@ css /* scss */ `
22423
22650
  `;
22424
22651
  class GaugeChartDesignPanel extends Component {
22425
22652
  static template = "o-spreadsheet-GaugeChartDesignPanel";
22426
- static components = { ColorPickerWidget, ValidationMessages };
22653
+ static components = { ColorPickerWidget, ChartErrorSection, ChartColor, ChartTitle, Section };
22654
+ static props = {
22655
+ figureId: String,
22656
+ definition: Object,
22657
+ updateChart: Function,
22658
+ canUpdateChart: Function,
22659
+ };
22427
22660
  state = useState({
22428
- title: "",
22429
22661
  openedMenu: undefined,
22430
22662
  sectionRuleDispatchResult: undefined,
22431
22663
  sectionRule: deepCopy(this.props.definition.sectionRule),
22432
22664
  });
22433
22665
  setup() {
22434
- this.state.title = _t(this.props.definition.title);
22435
22666
  useExternalListener(window, "click", this.closeMenus);
22436
22667
  }
22668
+ get title() {
22669
+ return _t(this.props.definition.title);
22670
+ }
22437
22671
  get designErrorMessages() {
22438
22672
  const cancelledReasons = [...(this.state.sectionRuleDispatchResult?.reasons || [])];
22439
22673
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
22440
22674
  }
22441
22675
  updateBackgroundColor(color) {
22442
- this.state.openedMenu = undefined;
22443
22676
  this.props.updateChart(this.props.figureId, {
22444
22677
  background: color,
22445
22678
  });
22446
22679
  }
22447
- updateTitle() {
22448
- this.props.updateChart(this.props.figureId, {
22449
- title: this.state.title,
22450
- });
22680
+ updateTitle(title) {
22681
+ this.props.updateChart(this.props.figureId, { title });
22451
22682
  }
22452
22683
  isRangeMinInvalid() {
22453
22684
  return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
@@ -22497,12 +22728,6 @@ class GaugeChartDesignPanel extends Component {
22497
22728
  this.state.openedMenu = undefined;
22498
22729
  }
22499
22730
  }
22500
- GaugeChartDesignPanel.props = {
22501
- figureId: String,
22502
- definition: Object,
22503
- updateChart: Function,
22504
- canUpdateChart: Function,
22505
- };
22506
22731
 
22507
22732
  class LineConfigPanel extends LineBarPieConfigPanel {
22508
22733
  static template = "o-spreadsheet-LineConfigPanel";
@@ -22513,24 +22738,42 @@ class LineConfigPanel extends LineBarPieConfigPanel {
22513
22738
  }
22514
22739
  return false;
22515
22740
  }
22516
- onUpdateLabelsAsText(ev) {
22741
+ get stackedLabel() {
22742
+ return _t("Stacked linechart");
22743
+ }
22744
+ get cumulativeLabel() {
22745
+ return _t("Cumulative data");
22746
+ }
22747
+ getLabelRangeOptions() {
22748
+ const options = super.getLabelRangeOptions();
22749
+ if (this.canTreatLabelsAsText) {
22750
+ options.push({
22751
+ name: "labelsAsText",
22752
+ value: this.props.definition.labelsAsText,
22753
+ label: _t("Treat labels as text"),
22754
+ onChange: this.onUpdateLabelsAsText.bind(this),
22755
+ });
22756
+ }
22757
+ return options;
22758
+ }
22759
+ onUpdateLabelsAsText(labelsAsText) {
22517
22760
  this.props.updateChart(this.props.figureId, {
22518
- labelsAsText: ev.target.checked,
22761
+ labelsAsText,
22519
22762
  });
22520
22763
  }
22521
- onUpdateStacked(ev) {
22764
+ onUpdateStacked(stacked) {
22522
22765
  this.props.updateChart(this.props.figureId, {
22523
- stacked: ev.target.checked,
22766
+ stacked,
22524
22767
  });
22525
22768
  }
22526
- onUpdateAggregated(ev) {
22769
+ onUpdateAggregated(aggregated) {
22527
22770
  this.props.updateChart(this.props.figureId, {
22528
- aggregated: ev.target.checked,
22771
+ aggregated,
22529
22772
  });
22530
22773
  }
22531
- onUpdateCumulative(ev) {
22774
+ onUpdateCumulative(cumulative) {
22532
22775
  this.props.updateChart(this.props.figureId, {
22533
- cumulative: ev.target.checked,
22776
+ cumulative,
22534
22777
  });
22535
22778
  }
22536
22779
  }
@@ -22541,7 +22784,13 @@ class LineChartDesignPanel extends LineBarPieDesignPanel {
22541
22784
 
22542
22785
  class ScorecardChartConfigPanel extends Component {
22543
22786
  static template = "o-spreadsheet-ScorecardChartConfigPanel";
22544
- static components = { SelectionInput, ValidationMessages };
22787
+ static components = { SelectionInput, ValidationMessages, ChartErrorSection, Section };
22788
+ static props = {
22789
+ figureId: String,
22790
+ definition: Object,
22791
+ updateChart: Function,
22792
+ canUpdateChart: Function,
22793
+ };
22545
22794
  state = useState({
22546
22795
  keyValueDispatchResult: undefined,
22547
22796
  baselineDispatchResult: undefined,
@@ -22593,28 +22842,27 @@ class ScorecardChartConfigPanel extends Component {
22593
22842
  this.props.updateChart(this.props.figureId, { baselineMode: ev.target.value });
22594
22843
  }
22595
22844
  }
22596
- ScorecardChartConfigPanel.props = {
22597
- figureId: String,
22598
- definition: Object,
22599
- updateChart: Function,
22600
- canUpdateChart: Function,
22601
- };
22602
22845
 
22603
22846
  class ScorecardChartDesignPanel extends Component {
22604
22847
  static template = "o-spreadsheet-ScorecardChartDesignPanel";
22605
- static components = { ColorPickerWidget };
22848
+ static components = { ColorPickerWidget, ChartColor, ChartTitle, Section };
22849
+ static props = {
22850
+ figureId: String,
22851
+ definition: Object,
22852
+ updateChart: Function,
22853
+ canUpdateChart: Function,
22854
+ };
22606
22855
  state = useState({
22607
- title: "",
22608
22856
  openedColorPicker: undefined,
22609
22857
  });
22610
22858
  setup() {
22611
- this.state.title = _t(this.props.definition.title);
22612
22859
  useExternalListener(window, "click", this.closeMenus);
22613
22860
  }
22614
- updateTitle() {
22615
- this.props.updateChart(this.props.figureId, {
22616
- title: this.state.title,
22617
- });
22861
+ get title() {
22862
+ return _t(this.props.definition.title);
22863
+ }
22864
+ updateTitle(title) {
22865
+ this.props.updateChart(this.props.figureId, { title });
22618
22866
  }
22619
22867
  translate(term) {
22620
22868
  return _t(term);
@@ -22648,12 +22896,6 @@ class ScorecardChartDesignPanel extends Component {
22648
22896
  this.state.openedColorPicker = undefined;
22649
22897
  }
22650
22898
  }
22651
- ScorecardChartDesignPanel.props = {
22652
- figureId: String,
22653
- definition: Object,
22654
- updateChart: Function,
22655
- canUpdateChart: Function,
22656
- };
22657
22899
 
22658
22900
  const chartSidePanelComponentRegistry = new Registry();
22659
22901
  chartSidePanelComponentRegistry
@@ -22704,6 +22946,8 @@ css /* scss */ `
22704
22946
  `;
22705
22947
  class ChartPanel extends Component {
22706
22948
  static template = "o-spreadsheet-ChartPanel";
22949
+ static components = { Section };
22950
+ static props = { onCloseSidePanel: Function };
22707
22951
  state;
22708
22952
  get figureId() {
22709
22953
  return this.state.figureId;
@@ -22790,9 +23034,6 @@ class ChartPanel extends Component {
22790
23034
  this.state.panel = panel;
22791
23035
  }
22792
23036
  }
22793
- ChartPanel.props = {
22794
- onCloseSidePanel: Function,
22795
- };
22796
23037
 
22797
23038
  css /* scss */ `
22798
23039
  .o-spreadsheet {
@@ -22903,6 +23144,9 @@ css /* scss */ `
22903
23144
  `;
22904
23145
  class IconPicker extends Component {
22905
23146
  static template = "o-spreadsheet-IconPicker";
23147
+ static props = {
23148
+ onIconPicked: Function,
23149
+ };
22906
23150
  icons = ICONS;
22907
23151
  iconSets = ICON_SETS;
22908
23152
  onIconClick(icon) {
@@ -22911,9 +23155,6 @@ class IconPicker extends Component {
22911
23155
  }
22912
23156
  }
22913
23157
  }
22914
- IconPicker.props = {
22915
- onIconPicked: Function,
22916
- };
22917
23158
 
22918
23159
  function useDragAndDropListItems() {
22919
23160
  let dndHelper;
@@ -23268,6 +23509,11 @@ css /* scss */ `
23268
23509
  `;
23269
23510
  class ConditionalFormatPreviewList extends Component {
23270
23511
  static template = "o-spreadsheet-ConditionalFormatPreviewList";
23512
+ static props = {
23513
+ conditionalFormats: Array,
23514
+ onPreviewClick: Function,
23515
+ onAddConditionalFormat: Function,
23516
+ };
23271
23517
  icons = ICONS;
23272
23518
  dragAndDrop = useDragAndDropListItems();
23273
23519
  cfListRef = useRef("cfList");
@@ -23348,11 +23594,6 @@ class ConditionalFormatPreviewList extends Component {
23348
23594
  }
23349
23595
  }
23350
23596
  }
23351
- ConditionalFormatPreviewList.props = {
23352
- conditionalFormats: Array,
23353
- onPreviewClick: Function,
23354
- onAddConditionalFormat: Function,
23355
- };
23356
23597
 
23357
23598
  css /* scss */ `
23358
23599
  label {
@@ -23525,11 +23766,16 @@ css /* scss */ `
23525
23766
  `;
23526
23767
  class ConditionalFormattingEditor extends Component {
23527
23768
  static template = "o-spreadsheet-ConditionalFormattingEditor";
23769
+ static props = {
23770
+ editedCf: { type: Object, optional: true },
23771
+ onExitEdition: Function,
23772
+ };
23528
23773
  static components = {
23529
23774
  SelectionInput,
23530
23775
  IconPicker,
23531
23776
  ColorPickerWidget,
23532
23777
  ConditionalFormatPreviewList,
23778
+ Section,
23533
23779
  };
23534
23780
  icons = ICONS;
23535
23781
  cellIsOperators = CellIsOperators;
@@ -23789,13 +24035,13 @@ class ConditionalFormattingEditor extends Component {
23789
24035
  this.state.rules.iconSet.icons[target] = icon;
23790
24036
  }
23791
24037
  }
23792
- ConditionalFormattingEditor.props = {
23793
- editedCf: { type: Object, optional: true },
23794
- onExitEdition: Function,
23795
- };
23796
24038
 
23797
24039
  class ConditionalFormattingPanel extends Component {
23798
24040
  static template = "o-spreadsheet-ConditionalFormattingPanel";
24041
+ static props = {
24042
+ selection: { type: Object, optional: true },
24043
+ onCloseSidePanel: Function,
24044
+ };
23799
24045
  static components = {
23800
24046
  ConditionalFormatPreviewList,
23801
24047
  ConditionalFormattingEditor,
@@ -23854,10 +24100,6 @@ class ConditionalFormattingPanel extends Component {
23854
24100
  this.state.editedCf = cf;
23855
24101
  }
23856
24102
  }
23857
- ConditionalFormattingPanel.props = {
23858
- selection: { type: Object, optional: true },
23859
- onCloseSidePanel: Function,
23860
- };
23861
24103
 
23862
24104
  css /* scss */ `
23863
24105
  .o-custom-currency {
@@ -23868,6 +24110,8 @@ css /* scss */ `
23868
24110
  `;
23869
24111
  class CustomCurrencyPanel extends Component {
23870
24112
  static template = "o-spreadsheet-CustomCurrencyPanel";
24113
+ static components = { Section };
24114
+ static props = { onCloseSidePanel: Function };
23871
24115
  availableCurrencies;
23872
24116
  state;
23873
24117
  setup() {
@@ -23990,9 +24234,6 @@ class CustomCurrencyPanel extends Component {
23990
24234
  return currency.name + (currency.code ? ` (${currency.code})` : "");
23991
24235
  }
23992
24236
  }
23993
- CustomCurrencyPanel.props = {
23994
- onCloseSidePanel: Function,
23995
- };
23996
24237
 
23997
24238
  css /* scss */ `
23998
24239
  .o-find-and-replace {
@@ -24012,11 +24253,20 @@ css /* scss */ `
24012
24253
  padding: 4px 0 4px 4px;
24013
24254
  }
24014
24255
  }
24256
+
24257
+ .o-matches-count div {
24258
+ text-overflow: ellipsis;
24259
+ overflow: hidden;
24260
+ white-space: nowrap;
24261
+ }
24015
24262
  }
24016
24263
  `;
24017
24264
  class FindAndReplacePanel extends Component {
24018
24265
  static template = "o-spreadsheet-FindAndReplacePanel";
24019
- static components = { SelectionInput };
24266
+ static components = { SelectionInput, Section, Checkbox };
24267
+ static props = {
24268
+ onCloseSidePanel: Function,
24269
+ };
24020
24270
  debounceTimeoutId;
24021
24271
  initialShowFormulaState = false;
24022
24272
  dataRange = "";
@@ -24091,19 +24341,16 @@ class FindAndReplacePanel extends Component {
24091
24341
  this.replace();
24092
24342
  }
24093
24343
  }
24094
- searchFormulas(ev) {
24095
- const showFormula = ev.target.checked;
24344
+ searchFormulas(showFormula) {
24096
24345
  this.env.model.dispatch("SET_FORMULA_VISIBILITY", {
24097
24346
  show: showFormula,
24098
24347
  });
24099
24348
  this.updateSearch({ searchFormulas: showFormula });
24100
24349
  }
24101
- searchExactMatch(ev) {
24102
- const exactMatch = ev.target.checked;
24350
+ searchExactMatch(exactMatch) {
24103
24351
  this.updateSearch({ exactMatch });
24104
24352
  }
24105
- searchMatchCase(ev) {
24106
- const matchCase = ev.target.checked;
24353
+ searchMatchCase(matchCase) {
24107
24354
  this.updateSearch({ matchCase });
24108
24355
  }
24109
24356
  changeSearchScope(ev) {
@@ -24156,9 +24403,6 @@ class FindAndReplacePanel extends Component {
24156
24403
  });
24157
24404
  }
24158
24405
  }
24159
- FindAndReplacePanel.props = {
24160
- onCloseSidePanel: Function,
24161
- };
24162
24406
 
24163
24407
  css /* scss */ `
24164
24408
  .o-more-formats-panel {
@@ -24190,13 +24434,13 @@ const DATE_FORMAT_ACTIONS = createActions([
24190
24434
  ]);
24191
24435
  class MoreFormatsPanel extends Component {
24192
24436
  static template = "o-spreadsheet-MoreFormatsPanel";
24437
+ static props = {
24438
+ onCloseSidePanel: Function,
24439
+ };
24193
24440
  get dateFormatsActions() {
24194
24441
  return DATE_FORMAT_ACTIONS;
24195
24442
  }
24196
24443
  }
24197
- MoreFormatsPanel.props = {
24198
- onCloseSidePanel: Function,
24199
- };
24200
24444
 
24201
24445
  css /* scss */ `
24202
24446
  .o-checkbox-selection {
@@ -24205,7 +24449,7 @@ css /* scss */ `
24205
24449
  `;
24206
24450
  class RemoveDuplicatesPanel extends Component {
24207
24451
  static template = "o-spreadsheet-RemoveDuplicatesPanel";
24208
- static components = { ValidationMessages };
24452
+ static components = { ValidationMessages, Section, Checkbox };
24209
24453
  state = useState({
24210
24454
  hasHeader: false,
24211
24455
  columns: {},
@@ -24294,6 +24538,8 @@ css /* scss */ `
24294
24538
  `;
24295
24539
  class SettingsPanel extends Component {
24296
24540
  static template = "o-spreadsheet-SettingsPanel";
24541
+ static components = { Section };
24542
+ static props = { onCloseSidePanel: Function };
24297
24543
  loadedLocales = [];
24298
24544
  setup() {
24299
24545
  onWillStart(() => this.loadLocales());
@@ -24342,9 +24588,6 @@ class SettingsPanel extends Component {
24342
24588
  return this.loadedLocales;
24343
24589
  }
24344
24590
  }
24345
- SettingsPanel.props = {
24346
- onCloseSidePanel: Function,
24347
- };
24348
24591
 
24349
24592
  const SplitToColumnsInteractiveContent = {
24350
24593
  SplitIsDestructive: _t("This will overwrite data in the subsequent columns. Split anyway?"),
@@ -24440,7 +24683,7 @@ dataValidationEvaluatorRegistry.add("dateIs", {
24440
24683
  return false;
24441
24684
  }
24442
24685
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
24443
- const today = jsDateToRoundNumber(new Date());
24686
+ const today = jsDateToRoundNumber(DateTime.now());
24444
24687
  return isDateBetween(dateValue, today, criterionValue);
24445
24688
  }
24446
24689
  return areDatesSameDay(dateValue, criterionValue);
@@ -24932,7 +25175,8 @@ const SEPARATORS = [
24932
25175
  ];
24933
25176
  class SplitIntoColumnsPanel extends Component {
24934
25177
  static template = "o-spreadsheet-SplitIntoColumnsPanel";
24935
- static components = { ValidationMessages };
25178
+ static components = { ValidationMessages, Section, Checkbox };
25179
+ static props = { onCloseSidePanel: Function };
24936
25180
  state = useState({ separatorValue: "auto", addNewColumns: false, customSeparator: "" });
24937
25181
  setup() {
24938
25182
  onWillUpdateProps(() => {
@@ -24954,10 +25198,8 @@ class SplitIntoColumnsPanel extends Component {
24954
25198
  return;
24955
25199
  this.state.customSeparator = ev.target.value;
24956
25200
  }
24957
- updateAddNewColumnsCheckbox(ev) {
24958
- if (!ev.target)
24959
- return;
24960
- this.state.addNewColumns = ev.target.checked;
25201
+ updateAddNewColumnsCheckbox(addNewColumns) {
25202
+ this.state.addNewColumns = addNewColumns;
24961
25203
  }
24962
25204
  confirm() {
24963
25205
  const result = interactiveSplitToColumns(this.env, this.separatorValue, this.state.addNewColumns);
@@ -25011,13 +25253,15 @@ class SplitIntoColumnsPanel extends Component {
25011
25253
  return !this.separatorValue || this.errorMessages.length > 0;
25012
25254
  }
25013
25255
  }
25014
- SplitIntoColumnsPanel.props = {
25015
- onCloseSidePanel: Function,
25016
- };
25017
25256
 
25018
25257
  /** This component looks like a select input, but on click it opens a Menu with the items given as props instead of a dropdown */
25019
25258
  class SelectMenu extends Component {
25020
25259
  static template = "o-spreadsheet-SelectMenu";
25260
+ static props = {
25261
+ menuItems: Array,
25262
+ selectedValue: String,
25263
+ class: { type: String, optional: true },
25264
+ };
25021
25265
  static components = { Menu };
25022
25266
  selectRef = useRef("select");
25023
25267
  selectRect = useAbsoluteBoundingRect(this.selectRef);
@@ -25037,13 +25281,12 @@ class SelectMenu extends Component {
25037
25281
  };
25038
25282
  }
25039
25283
  }
25040
- SelectMenu.props = {
25041
- menuItems: Array,
25042
- selectedValue: String,
25043
- class: { type: String, optional: true },
25044
- };
25045
25284
 
25046
25285
  class DataValidationCriterionForm extends Component {
25286
+ static props = {
25287
+ criterion: Object,
25288
+ onCriterionChanged: Function,
25289
+ };
25047
25290
  setup() {
25048
25291
  onMounted(() => {
25049
25292
  interactiveStopEdition(this.env);
@@ -25057,10 +25300,6 @@ class DataValidationCriterionForm extends Component {
25057
25300
  this.props.onCriterionChanged(filteredCriterion);
25058
25301
  }
25059
25302
  }
25060
- DataValidationCriterionForm.props = {
25061
- criterion: Object,
25062
- onCriterionChanged: Function,
25063
- };
25064
25303
 
25065
25304
  css /* scss */ `
25066
25305
  .o-dv-input {
@@ -25075,6 +25314,15 @@ css /* scss */ `
25075
25314
  `;
25076
25315
  class DataValidationInput extends Component {
25077
25316
  static template = "o-spreadsheet-DataValidationInput";
25317
+ static props = {
25318
+ value: { type: String, optional: true },
25319
+ criterionType: String,
25320
+ onValueChanged: Function,
25321
+ onKeyDown: { type: Function, optional: true },
25322
+ focused: { type: Boolean, optional: true },
25323
+ onBlur: { type: Function, optional: true },
25324
+ onFocus: { type: Function, optional: true },
25325
+ };
25078
25326
  static defaultProps = {
25079
25327
  value: "",
25080
25328
  onKeyDown: () => { },
@@ -25113,15 +25361,6 @@ class DataValidationInput extends Component {
25113
25361
  return this.env.model.getters.getDataValidationInvalidCriterionValueMessage(this.props.criterionType, canonicalizeContent(this.props.value, this.env.model.getters.getLocale()));
25114
25362
  }
25115
25363
  }
25116
- DataValidationInput.props = {
25117
- value: { type: String, optional: true },
25118
- criterionType: String,
25119
- onValueChanged: Function,
25120
- onKeyDown: { type: Function, optional: true },
25121
- focused: { type: Boolean, optional: true },
25122
- onBlur: { type: Function, optional: true },
25123
- onFocus: { type: Function, optional: true },
25124
- };
25125
25364
 
25126
25365
  const DATES_VALUES = {
25127
25366
  today: _t("today"),
@@ -25457,7 +25696,11 @@ css /* scss */ `
25457
25696
  `;
25458
25697
  class DataValidationEditor extends Component {
25459
25698
  static template = "o-spreadsheet-DataValidationEditor";
25460
- static components = { SelectionInput, SelectMenu };
25699
+ static components = { SelectionInput, SelectMenu, Section };
25700
+ static props = {
25701
+ rule: { type: Object, optional: true },
25702
+ onExit: Function,
25703
+ };
25461
25704
  state = useState({ rule: this.defaultDataValidationRule });
25462
25705
  setup() {
25463
25706
  if (this.props.rule) {
@@ -25533,10 +25776,6 @@ class DataValidationEditor extends Component {
25533
25776
  return dataValidationPanelCriteriaRegistry.get(this.state.rule.criterion.type).component;
25534
25777
  }
25535
25778
  }
25536
- DataValidationEditor.props = {
25537
- rule: { type: Object, optional: true },
25538
- onExit: Function,
25539
- };
25540
25779
 
25541
25780
  css /* scss */ `
25542
25781
  .o-sidePanel {
@@ -25566,6 +25805,10 @@ css /* scss */ `
25566
25805
  `;
25567
25806
  class DataValidationPreview extends Component {
25568
25807
  static template = "o-spreadsheet-DataValidationPreview";
25808
+ static props = {
25809
+ onClick: Function,
25810
+ rule: Object,
25811
+ };
25569
25812
  deleteDataValidation() {
25570
25813
  const sheetId = this.env.model.getters.getActiveSheetId();
25571
25814
  this.env.model.dispatch("REMOVE_DATA_VALIDATION_RULE", { sheetId, id: this.props.rule.id });
@@ -25582,13 +25825,12 @@ class DataValidationPreview extends Component {
25582
25825
  .getPreview(this.props.rule.criterion, this.env.model.getters);
25583
25826
  }
25584
25827
  }
25585
- DataValidationPreview.props = {
25586
- onClick: Function,
25587
- rule: Object,
25588
- };
25589
25828
 
25590
25829
  class DataValidationPanel extends Component {
25591
25830
  static template = "o-spreadsheet-DataValidationPanel";
25831
+ static props = {
25832
+ onCloseSidePanel: Function,
25833
+ };
25592
25834
  static components = { DataValidationPreview, DataValidationEditor };
25593
25835
  state = useState({ mode: "list", activeRule: undefined });
25594
25836
  onPreviewClick(id) {
@@ -25618,9 +25860,6 @@ class DataValidationPanel extends Component {
25618
25860
  return this.env.model.getters.getDataValidationRules(sheetId);
25619
25861
  }
25620
25862
  }
25621
- DataValidationPanel.props = {
25622
- onCloseSidePanel: Function,
25623
- };
25624
25863
 
25625
25864
  const sidePanelRegistry = new Registry();
25626
25865
  sidePanelRegistry.add("ConditionalFormatting", {
@@ -25752,6 +25991,13 @@ css /*SCSS*/ `
25752
25991
  `;
25753
25992
  class FigureComponent extends Component {
25754
25993
  static template = "o-spreadsheet-FigureComponent";
25994
+ static props = {
25995
+ figure: Object,
25996
+ style: { type: String, optional: true },
25997
+ onFigureDeleted: { type: Function, optional: true },
25998
+ onMouseDown: { type: Function, optional: true },
25999
+ onClickAnchor: { type: Function, optional: true },
26000
+ };
25755
26001
  static components = { Menu };
25756
26002
  static defaultProps = {
25757
26003
  onFigureDeleted: () => { },
@@ -25894,13 +26140,6 @@ class FigureComponent extends Component {
25894
26140
  .menuBuilder(this.props.figure.id, this.props.onFigureDeleted, this.env);
25895
26141
  }
25896
26142
  }
25897
- FigureComponent.props = {
25898
- figure: Object,
25899
- style: { type: String, optional: true },
25900
- onFigureDeleted: { type: Function, optional: true },
25901
- onMouseDown: { type: Function, optional: true },
25902
- onClickAnchor: { type: Function, optional: true },
25903
- };
25904
26143
 
25905
26144
  const ToggleGroupInteractiveContent = {
25906
26145
  CannotHideAllRows: _t("Cannot hide all the rows of a sheet."),
@@ -26038,6 +26277,10 @@ css /* scss */ `
26038
26277
  `;
26039
26278
  class Autofill extends Component {
26040
26279
  static template = "o-spreadsheet-Autofill";
26280
+ static props = {
26281
+ position: Object,
26282
+ isVisible: Boolean,
26283
+ };
26041
26284
  state = useState({
26042
26285
  position: { left: 0, top: 0 },
26043
26286
  handler: false,
@@ -26106,18 +26349,14 @@ class Autofill extends Component {
26106
26349
  this.env.model.dispatch("AUTOFILL_AUTO");
26107
26350
  }
26108
26351
  }
26109
- Autofill.props = {
26110
- position: Object,
26111
- isVisible: Boolean,
26112
- };
26113
26352
  class TooltipComponent extends Component {
26353
+ static props = {
26354
+ content: String,
26355
+ };
26114
26356
  static template = xml /* xml */ `
26115
26357
  <div t-esc="props.content"/>
26116
26358
  `;
26117
26359
  }
26118
- TooltipComponent.props = {
26119
- content: String,
26120
- };
26121
26360
 
26122
26361
  css /* scss */ `
26123
26362
  .o-client-tag {
@@ -26131,6 +26370,13 @@ css /* scss */ `
26131
26370
  `;
26132
26371
  class ClientTag extends Component {
26133
26372
  static template = "o-spreadsheet-ClientTag";
26373
+ static props = {
26374
+ active: Boolean,
26375
+ name: String,
26376
+ color: String,
26377
+ col: Number,
26378
+ row: Number,
26379
+ };
26134
26380
  get tagStyle() {
26135
26381
  const { col, row, color } = this.props;
26136
26382
  const { height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
@@ -26148,13 +26394,6 @@ class ClientTag extends Component {
26148
26394
  });
26149
26395
  }
26150
26396
  }
26151
- ClientTag.props = {
26152
- active: Boolean,
26153
- name: String,
26154
- color: String,
26155
- col: Number,
26156
- row: Number,
26157
- };
26158
26397
 
26159
26398
  function getHtmlContentFromPattern(pattern, value, highlightColor, className) {
26160
26399
  const pendingHtmlContent = [];
@@ -26194,14 +26433,14 @@ css /* scss */ `
26194
26433
  `;
26195
26434
  class TextValueProvider extends Component {
26196
26435
  static template = "o-spreadsheet-TextValueProvider";
26436
+ static props = {
26437
+ values: Array,
26438
+ selectedIndex: { type: Number, optional: true },
26439
+ getHtmlContent: Function,
26440
+ onValueSelected: Function,
26441
+ onValueHovered: Function,
26442
+ };
26197
26443
  }
26198
- TextValueProvider.props = {
26199
- values: Array,
26200
- selectedIndex: { type: Number, optional: true },
26201
- getHtmlContent: Function,
26202
- onValueSelected: Function,
26203
- onValueHovered: Function,
26204
- };
26205
26444
 
26206
26445
  class ContentEditableHelper {
26207
26446
  // todo make el private and expose dedicated methods
@@ -26563,6 +26802,11 @@ css /* scss */ `
26563
26802
  `;
26564
26803
  class FunctionDescriptionProvider extends Component {
26565
26804
  static template = "o-spreadsheet-FunctionDescriptionProvider";
26805
+ static props = {
26806
+ functionName: String,
26807
+ functionDescription: Object,
26808
+ argToFocus: Number,
26809
+ };
26566
26810
  assistantState = useState({
26567
26811
  allowCellSelectionBehind: false,
26568
26812
  });
@@ -26587,11 +26831,6 @@ class FunctionDescriptionProvider extends Component {
26587
26831
  }, 2000);
26588
26832
  }
26589
26833
  }
26590
- FunctionDescriptionProvider.props = {
26591
- functionName: String,
26592
- functionDescription: Object,
26593
- argToFocus: Number,
26594
- };
26595
26834
 
26596
26835
  const functions$2 = functionRegistry.content;
26597
26836
  const ASSISTANT_WIDTH = 300;
@@ -26657,6 +26896,16 @@ css /* scss */ `
26657
26896
  `;
26658
26897
  class Composer extends Component {
26659
26898
  static template = "o-spreadsheet-Composer";
26899
+ static props = {
26900
+ focus: {
26901
+ validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
26902
+ },
26903
+ onComposerContentFocused: Function,
26904
+ inputStyle: { type: String, optional: true },
26905
+ rect: { type: Object, optional: true },
26906
+ delimitation: { type: Object, optional: true },
26907
+ onComposerUnmounted: { type: Function, optional: true },
26908
+ };
26660
26909
  static components = { TextValueProvider, FunctionDescriptionProvider };
26661
26910
  static defaultProps = {
26662
26911
  inputStyle: "",
@@ -27213,14 +27462,6 @@ class Composer extends Component {
27213
27462
  this.autoCompleteState.getHtmlContent = (value) => [{ value }];
27214
27463
  }
27215
27464
  }
27216
- Composer.props = {
27217
- focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
27218
- onComposerContentFocused: Function,
27219
- inputStyle: { type: String, optional: true },
27220
- rect: { type: Object, optional: true },
27221
- delimitation: { type: Object, optional: true },
27222
- onComposerUnmounted: { type: Function, optional: true },
27223
- };
27224
27465
 
27225
27466
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
27226
27467
  const GRID_CELL_REFERENCE_TOP_OFFSET = 28;
@@ -27252,6 +27493,14 @@ css /* scss */ `
27252
27493
  */
27253
27494
  class GridComposer extends Component {
27254
27495
  static template = "o-spreadsheet-GridComposer";
27496
+ static props = {
27497
+ focus: {
27498
+ validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
27499
+ },
27500
+ onComposerUnmounted: Function,
27501
+ onComposerContentFocused: Function,
27502
+ gridDims: Object,
27503
+ };
27255
27504
  static components = { Composer };
27256
27505
  gridComposerRef;
27257
27506
  zone;
@@ -27358,22 +27607,22 @@ class GridComposer extends Component {
27358
27607
  });
27359
27608
  }
27360
27609
  }
27361
- GridComposer.props = {
27362
- focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
27363
- onComposerUnmounted: Function,
27364
- onComposerContentFocused: Function,
27365
- gridDims: Object,
27366
- };
27367
27610
 
27368
- const CSS$1 = css /* scss */ `
27611
+ css /* scss */ `
27369
27612
  .o-grid-cell-icon {
27370
27613
  width: ${GRID_ICON_EDGE_LENGTH}px;
27371
27614
  height: ${GRID_ICON_EDGE_LENGTH}px;
27372
27615
  }
27373
27616
  `;
27374
27617
  class GridCellIcon extends Component {
27375
- static style = CSS$1;
27376
27618
  static template = "o-spreadsheet-GridCellIcon";
27619
+ static props = {
27620
+ cellPosition: Object,
27621
+ horizontalAlign: { type: String, optional: true },
27622
+ verticalAlign: { type: String, optional: true },
27623
+ offset: { type: Object, optional: true },
27624
+ slots: Object,
27625
+ };
27377
27626
  get iconStyle() {
27378
27627
  const x = this.getIconHorizontalPosition();
27379
27628
  const y = this.getIconVerticalPosition();
@@ -27422,15 +27671,8 @@ class GridCellIcon extends Component {
27422
27671
  return !(rect.width === 0 || rect.height === 0);
27423
27672
  }
27424
27673
  }
27425
- GridCellIcon.props = {
27426
- cellPosition: Object,
27427
- horizontalAlign: { type: String, optional: true },
27428
- verticalAlign: { type: String, optional: true },
27429
- offset: { type: Object, optional: true },
27430
- slots: Object,
27431
- };
27432
27674
 
27433
- const CSS = css /* scss */ `
27675
+ css /* scss */ `
27434
27676
  .o-filter-icon {
27435
27677
  color: ${FILTERS_COLOR};
27436
27678
  display: flex;
@@ -27445,8 +27687,10 @@ const CSS = css /* scss */ `
27445
27687
  }
27446
27688
  `;
27447
27689
  class FilterIcon extends Component {
27448
- static style = CSS;
27449
27690
  static template = "o-spreadsheet-FilterIcon";
27691
+ static props = {
27692
+ cellPosition: Object,
27693
+ };
27450
27694
  onClick() {
27451
27695
  const position = this.props.cellPosition;
27452
27696
  const activePopoverType = this.env.model.getters.getPersistentPopoverTypeAtPosition(position);
@@ -27465,12 +27709,12 @@ class FilterIcon extends Component {
27465
27709
  return this.env.model.getters.isFilterActive(this.props.cellPosition);
27466
27710
  }
27467
27711
  }
27468
- FilterIcon.props = {
27469
- cellPosition: Object,
27470
- };
27471
27712
 
27472
27713
  class FilterIconsOverlay extends Component {
27473
27714
  static template = "o-spreadsheet-FilterIconsOverlay";
27715
+ static props = {
27716
+ gridPosition: { type: Object, optional: true },
27717
+ };
27474
27718
  static components = {
27475
27719
  GridCellIcon,
27476
27720
  FilterIcon,
@@ -27484,9 +27728,6 @@ class FilterIconsOverlay extends Component {
27484
27728
  return headerPositions.map((position) => ({ sheetId, ...position }));
27485
27729
  }
27486
27730
  }
27487
- FilterIconsOverlay.props = {
27488
- gridPosition: { type: Object, optional: true },
27489
- };
27490
27731
 
27491
27732
  const CHECKBOX_WIDTH = 15;
27492
27733
  const MARGIN = (GRID_ICON_EDGE_LENGTH - CHECKBOX_WIDTH) / 2;
@@ -27500,6 +27741,9 @@ css /* scss */ `
27500
27741
  `;
27501
27742
  class DataValidationCheckbox extends Component {
27502
27743
  static template = "o-spreadsheet-DataValidationCheckbox";
27744
+ static props = {
27745
+ cellPosition: Object,
27746
+ };
27503
27747
  onCheckboxChange(ev) {
27504
27748
  const newValue = ev.target.checked;
27505
27749
  const { sheetId, col, row } = this.props.cellPosition;
@@ -27514,9 +27758,6 @@ class DataValidationCheckbox extends Component {
27514
27758
  return !!cell?.isFormula;
27515
27759
  }
27516
27760
  }
27517
- DataValidationCheckbox.props = {
27518
- cellPosition: Object,
27519
- };
27520
27761
 
27521
27762
  const ICON_WIDTH = 13;
27522
27763
  css /* scss */ `
@@ -27539,18 +27780,19 @@ css /* scss */ `
27539
27780
  `;
27540
27781
  class DataValidationListIcon extends Component {
27541
27782
  static template = "o-spreadsheet-DataValidationListIcon";
27783
+ static props = {
27784
+ cellPosition: Object,
27785
+ };
27542
27786
  onClick() {
27543
27787
  const { col, row } = this.props.cellPosition;
27544
27788
  this.env.model.selection.selectCell(col, row);
27545
27789
  this.env.startCellEdition();
27546
27790
  }
27547
27791
  }
27548
- DataValidationListIcon.props = {
27549
- cellPosition: Object,
27550
- };
27551
27792
 
27552
27793
  class DataValidationOverlay extends Component {
27553
27794
  static template = "o-spreadsheet-DataValidationOverlay";
27795
+ static props = {};
27554
27796
  static components = { GridCellIcon, DataValidationCheckbox, DataValidationListIcon };
27555
27797
  get checkBoxCellPositions() {
27556
27798
  return this.env.model.getters.getDataValidationCheckBoxCellPositions();
@@ -27561,7 +27803,6 @@ class DataValidationOverlay extends Component {
27561
27803
  : this.env.model.getters.getDataValidationListCellsPositions();
27562
27804
  }
27563
27805
  }
27564
- DataValidationOverlay.props = {};
27565
27806
 
27566
27807
  /**
27567
27808
  * Transform a figure with coordinates from the model, to coordinates as they are shown on the screen,
@@ -27897,6 +28138,9 @@ css /*SCSS*/ `
27897
28138
  */
27898
28139
  class FiguresContainer extends Component {
27899
28140
  static template = "o-spreadsheet-FiguresContainer";
28141
+ static props = {
28142
+ onFigureDeleted: Function,
28143
+ };
27900
28144
  static components = { FigureComponent };
27901
28145
  dnd = useState({
27902
28146
  draggedFigure: undefined,
@@ -28146,9 +28390,6 @@ class FiguresContainer extends Component {
28146
28390
  }
28147
28391
  }
28148
28392
  }
28149
- FiguresContainer.props = {
28150
- onFigureDeleted: Function,
28151
- };
28152
28393
 
28153
28394
  css /* scss */ `
28154
28395
  .o-grid-add-rows {
@@ -28167,6 +28408,9 @@ css /* scss */ `
28167
28408
  `;
28168
28409
  class GridAddRowsFooter extends Component {
28169
28410
  static template = "o-spreadsheet-GridAddRowsFooter";
28411
+ static props = {
28412
+ focusGrid: Function,
28413
+ };
28170
28414
  static components = { ValidationMessages };
28171
28415
  inputRef = useRef("inputRef");
28172
28416
  state = useState({
@@ -28233,9 +28477,6 @@ class GridAddRowsFooter extends Component {
28233
28477
  this.props.focusGrid();
28234
28478
  }
28235
28479
  }
28236
- GridAddRowsFooter.props = {
28237
- focusGrid: Function,
28238
- };
28239
28480
 
28240
28481
  /**
28241
28482
  * Manages an event listener on a ref. Useful for hooks that want to manage
@@ -28391,6 +28632,16 @@ function useTouchMove(gridRef, handler, canMoveUp) {
28391
28632
  }
28392
28633
  class GridOverlay extends Component {
28393
28634
  static template = "o-spreadsheet-GridOverlay";
28635
+ static props = {
28636
+ onCellHovered: { type: Function, optional: true },
28637
+ onCellDoubleClicked: { type: Function, optional: true },
28638
+ onCellClicked: { type: Function, optional: true },
28639
+ onCellRightClicked: { type: Function, optional: true },
28640
+ onGridResized: { type: Function, optional: true },
28641
+ onFigureDeleted: { type: Function, optional: true },
28642
+ onGridMoved: Function,
28643
+ gridOverlayDimensions: String,
28644
+ };
28394
28645
  static components = { FiguresContainer, DataValidationOverlay, GridAddRowsFooter };
28395
28646
  static defaultProps = {
28396
28647
  onCellHovered: () => { },
@@ -28442,7 +28693,10 @@ class GridOverlay extends Component {
28442
28693
  return;
28443
28694
  }
28444
28695
  const [col, row] = this.getCartesianCoordinates(ev);
28445
- this.props.onCellClicked(col, row, { shiftKey: ev.shiftKey, ctrlKey: ev.ctrlKey });
28696
+ this.props.onCellClicked(col, row, {
28697
+ expandZone: ev.shiftKey,
28698
+ addZone: isCtrlKey(ev),
28699
+ });
28446
28700
  }
28447
28701
  onDoubleClick(ev) {
28448
28702
  const [col, row] = this.getCartesianCoordinates(ev);
@@ -28461,19 +28715,15 @@ class GridOverlay extends Component {
28461
28715
  return [colIndex, rowIndex];
28462
28716
  }
28463
28717
  }
28464
- GridOverlay.props = {
28465
- onCellHovered: { type: Function, optional: true },
28466
- onCellDoubleClicked: { type: Function, optional: true },
28467
- onCellClicked: { type: Function, optional: true },
28468
- onCellRightClicked: { type: Function, optional: true },
28469
- onGridResized: { type: Function, optional: true },
28470
- onFigureDeleted: { type: Function, optional: true },
28471
- onGridMoved: Function,
28472
- gridOverlayDimensions: String,
28473
- };
28474
28718
 
28475
28719
  class GridPopover extends Component {
28476
28720
  static template = "o-spreadsheet-GridPopover";
28721
+ static props = {
28722
+ hoveredCell: Object,
28723
+ onClosePopover: Function,
28724
+ onMouseWheel: Function,
28725
+ gridRect: Object,
28726
+ };
28477
28727
  static components = { Popover };
28478
28728
  zIndex = ComponentsImportance.GridPopover;
28479
28729
  get cellPopover() {
@@ -28493,14 +28743,11 @@ class GridPopover extends Component {
28493
28743
  };
28494
28744
  }
28495
28745
  }
28496
- GridPopover.props = {
28497
- hoveredCell: Object,
28498
- onClosePopover: Function,
28499
- onMouseWheel: Function,
28500
- gridRect: Object,
28501
- };
28502
28746
 
28503
28747
  class AbstractResizer extends Component {
28748
+ static props = {
28749
+ onOpenContextMenu: Function,
28750
+ };
28504
28751
  PADDING = 0;
28505
28752
  MAX_SIZE_MARGIN = 0;
28506
28753
  MIN_ELEMENT_SIZE = 0;
@@ -28672,7 +28919,7 @@ class AbstractResizer extends Component {
28672
28919
  this._increaseSelection(index);
28673
28920
  }
28674
28921
  else {
28675
- this._selectElement(index, ev.ctrlKey);
28922
+ this._selectElement(index, isCtrlKey(ev));
28676
28923
  }
28677
28924
  this.lastSelectedElementIndex = index;
28678
28925
  const mouseMoveSelect = (col, row) => {
@@ -28757,10 +29004,10 @@ css /* scss */ `
28757
29004
  }
28758
29005
  }
28759
29006
  `;
28760
- AbstractResizer.props = {
28761
- onOpenContextMenu: Function,
28762
- };
28763
29007
  class ColResizer extends AbstractResizer {
29008
+ static props = {
29009
+ onOpenContextMenu: Function,
29010
+ };
28764
29011
  static template = "o-spreadsheet-ColResizer";
28765
29012
  colResizerRef;
28766
29013
  setup() {
@@ -28829,8 +29076,8 @@ class ColResizer extends AbstractResizer {
28829
29076
  this.env.raiseError(MergeErrorMessage);
28830
29077
  }
28831
29078
  }
28832
- _selectElement(index, ctrlKey) {
28833
- this.env.model.selection.selectColumn(index, ctrlKey ? "newAnchor" : "overrideSelection");
29079
+ _selectElement(index, addDistinctHeader) {
29080
+ this.env.model.selection.selectColumn(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
28834
29081
  }
28835
29082
  _increaseSelection(index) {
28836
29083
  this.env.model.selection.selectColumn(index, "updateAnchor");
@@ -28922,10 +29169,10 @@ css /* scss */ `
28922
29169
  }
28923
29170
  }
28924
29171
  `;
28925
- ColResizer.props = {
28926
- onOpenContextMenu: Function,
28927
- };
28928
29172
  class RowResizer extends AbstractResizer {
29173
+ static props = {
29174
+ onOpenContextMenu: Function,
29175
+ };
28929
29176
  static template = "o-spreadsheet-RowResizer";
28930
29177
  setup() {
28931
29178
  super.setup();
@@ -28994,8 +29241,8 @@ class RowResizer extends AbstractResizer {
28994
29241
  this.env.raiseError(MergeErrorMessage);
28995
29242
  }
28996
29243
  }
28997
- _selectElement(index, ctrlKey) {
28998
- this.env.model.selection.selectRow(index, ctrlKey ? "newAnchor" : "overrideSelection");
29244
+ _selectElement(index, addDistinctHeader) {
29245
+ this.env.model.selection.selectRow(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
28999
29246
  }
29000
29247
  _increaseSelection(index) {
29001
29248
  this.env.model.selection.selectRow(index, "updateAnchor");
@@ -29046,19 +29293,16 @@ css /* scss */ `
29046
29293
  }
29047
29294
  }
29048
29295
  `;
29049
- RowResizer.props = {
29050
- onOpenContextMenu: Function,
29051
- };
29052
29296
  class HeadersOverlay extends Component {
29297
+ static props = {
29298
+ onOpenContextMenu: Function,
29299
+ };
29053
29300
  static template = "o-spreadsheet-HeadersOverlay";
29054
29301
  static components = { ColResizer, RowResizer };
29055
29302
  selectAll() {
29056
29303
  this.env.model.selection.selectAll();
29057
29304
  }
29058
29305
  }
29059
- HeadersOverlay.props = {
29060
- onOpenContextMenu: Function,
29061
- };
29062
29306
 
29063
29307
  function useGridDrawing(refName, model, canvasSize) {
29064
29308
  const canvasRef = useRef(refName);
@@ -29116,6 +29360,12 @@ css /* scss */ `
29116
29360
  `;
29117
29361
  class Border extends Component {
29118
29362
  static template = "o-spreadsheet-Border";
29363
+ static props = {
29364
+ zone: Object,
29365
+ orientation: String,
29366
+ isMoving: Boolean,
29367
+ onMoveHighlight: Function,
29368
+ };
29119
29369
  get style() {
29120
29370
  const isTop = ["n", "w", "e"].includes(this.props.orientation);
29121
29371
  const isLeft = ["n", "w", "s"].includes(this.props.orientation);
@@ -29144,12 +29394,6 @@ class Border extends Component {
29144
29394
  this.props.onMoveHighlight(ev.clientX, ev.clientY);
29145
29395
  }
29146
29396
  }
29147
- Border.props = {
29148
- zone: Object,
29149
- orientation: String,
29150
- isMoving: Boolean,
29151
- onMoveHighlight: Function,
29152
- };
29153
29397
 
29154
29398
  css /* scss */ `
29155
29399
  .o-corner {
@@ -29176,6 +29420,13 @@ css /* scss */ `
29176
29420
  `;
29177
29421
  class Corner extends Component {
29178
29422
  static template = "o-spreadsheet-Corner";
29423
+ static props = {
29424
+ zone: Object,
29425
+ color: String,
29426
+ orientation: String,
29427
+ isResizing: Boolean,
29428
+ onResizeHighlight: Function,
29429
+ };
29179
29430
  isTop = this.props.orientation[0] === "n";
29180
29431
  isLeft = this.props.orientation[1] === "w";
29181
29432
  get style() {
@@ -29204,13 +29455,6 @@ class Corner extends Component {
29204
29455
  this.props.onResizeHighlight(this.isLeft, this.isTop);
29205
29456
  }
29206
29457
  }
29207
- Corner.props = {
29208
- zone: Object,
29209
- color: String,
29210
- orientation: String,
29211
- isResizing: Boolean,
29212
- onResizeHighlight: Function,
29213
- };
29214
29458
 
29215
29459
  css /*SCSS*/ `
29216
29460
  .o-highlight {
@@ -29219,6 +29463,10 @@ css /*SCSS*/ `
29219
29463
  `;
29220
29464
  class Highlight extends Component {
29221
29465
  static template = "o-spreadsheet-Highlight";
29466
+ static props = {
29467
+ zone: Object,
29468
+ color: String,
29469
+ };
29222
29470
  static components = {
29223
29471
  Corner,
29224
29472
  Border,
@@ -29302,10 +29550,6 @@ class Highlight extends Component {
29302
29550
  dragAndDropBeyondTheViewport(this.env, mouseMove, mouseUp);
29303
29551
  }
29304
29552
  }
29305
- Highlight.props = {
29306
- zone: Object,
29307
- color: String,
29308
- };
29309
29553
 
29310
29554
  let ScrollBar$1 = class ScrollBar {
29311
29555
  direction;
@@ -29345,6 +29589,14 @@ css /* scss */ `
29345
29589
  }
29346
29590
  `;
29347
29591
  class ScrollBar extends Component {
29592
+ static props = {
29593
+ width: { type: Number, optional: true },
29594
+ height: { type: Number, optional: true },
29595
+ direction: String,
29596
+ position: Object,
29597
+ offset: Number,
29598
+ onScroll: Function,
29599
+ };
29348
29600
  static template = xml /*xml*/ `
29349
29601
  <div
29350
29602
  t-attf-class="o-scrollbar {{props.direction}}"
@@ -29388,16 +29640,11 @@ class ScrollBar extends Component {
29388
29640
  }
29389
29641
  }
29390
29642
  }
29391
- ScrollBar.props = {
29392
- width: { type: Number, optional: true },
29393
- height: { type: Number, optional: true },
29394
- direction: String,
29395
- position: Object,
29396
- offset: Number,
29397
- onScroll: Function,
29398
- };
29399
29643
 
29400
29644
  class HorizontalScrollBar extends Component {
29645
+ static props = {
29646
+ leftOffset: { type: Number, optional: true },
29647
+ };
29401
29648
  static components = { ScrollBar };
29402
29649
  static template = xml /*xml*/ `
29403
29650
  <ScrollBar
@@ -29438,11 +29685,11 @@ class HorizontalScrollBar extends Component {
29438
29685
  });
29439
29686
  }
29440
29687
  }
29441
- HorizontalScrollBar.props = {
29442
- leftOffset: { type: Number, optional: true },
29443
- };
29444
29688
 
29445
29689
  class VerticalScrollBar extends Component {
29690
+ static props = {
29691
+ topOffset: { type: Number, optional: true },
29692
+ };
29446
29693
  static components = { ScrollBar };
29447
29694
  static template = xml /*xml*/ `
29448
29695
  <ScrollBar
@@ -29483,9 +29730,6 @@ class VerticalScrollBar extends Component {
29483
29730
  });
29484
29731
  }
29485
29732
  }
29486
- VerticalScrollBar.props = {
29487
- topOffset: { type: Number, optional: true },
29488
- };
29489
29733
 
29490
29734
  const registries$1 = {
29491
29735
  ROW: rowMenuRegistry,
@@ -29499,6 +29743,13 @@ const registries$1 = {
29499
29743
  // -----------------------------------------------------------------------------
29500
29744
  class Grid extends Component {
29501
29745
  static template = "o-spreadsheet-Grid";
29746
+ static props = {
29747
+ sidePanelIsOpen: Boolean,
29748
+ exposeFocus: Function,
29749
+ focusComposer: String,
29750
+ onComposerContentFocused: Function,
29751
+ onGridComposerCellFocused: Function,
29752
+ };
29502
29753
  static components = {
29503
29754
  GridComposer,
29504
29755
  GridOverlay,
@@ -29688,7 +29939,7 @@ class Grid extends Component {
29688
29939
  "Ctrl+Shift+E": () => this.setHorizontalAlign("center"),
29689
29940
  "Ctrl+Shift+L": () => this.setHorizontalAlign("left"),
29690
29941
  "Ctrl+Shift+R": () => this.setHorizontalAlign("right"),
29691
- "Ctrl+Shift+V": () => PASTE_VALUE_ACTION(this.env),
29942
+ "Ctrl+Shift+V": () => PASTE_AS_VALUE_ACTION(this.env),
29692
29943
  "Ctrl+Shift+<": () => this.clearFormatting(),
29693
29944
  "Ctrl+<": () => this.clearFormatting(),
29694
29945
  "Ctrl+Shift+ ": () => {
@@ -29796,17 +30047,17 @@ class Grid extends Component {
29796
30047
  // ---------------------------------------------------------------------------
29797
30048
  // Zone selection with mouse
29798
30049
  // ---------------------------------------------------------------------------
29799
- onCellClicked(col, row, { ctrlKey, shiftKey }) {
30050
+ onCellClicked(col, row, { addZone, expandZone }) {
29800
30051
  if (this.env.model.getters.hasOpenedPopover()) {
29801
30052
  this.closeOpenedPopover();
29802
30053
  }
29803
30054
  if (this.env.model.getters.getEditionMode() === "editing") {
29804
30055
  interactiveStopEdition(this.env);
29805
30056
  }
29806
- if (shiftKey) {
30057
+ if (expandZone) {
29807
30058
  this.env.model.selection.setAnchorCorner(col, row);
29808
30059
  }
29809
- else if (ctrlKey) {
30060
+ else if (addZone) {
29810
30061
  this.env.model.selection.addCellToSelection(col, row);
29811
30062
  }
29812
30063
  else {
@@ -30103,13 +30354,6 @@ class Grid extends Component {
30103
30354
  }
30104
30355
  }
30105
30356
  }
30106
- Grid.props = {
30107
- sidePanelIsOpen: Boolean,
30108
- exposeFocus: Function,
30109
- focusComposer: String,
30110
- onComposerContentFocused: Function,
30111
- onGridComposerCellFocused: Function,
30112
- };
30113
30357
 
30114
30358
  /**
30115
30359
  * Represent a raw XML string
@@ -30609,7 +30853,7 @@ const XLSX_FORMATS_CONVERSION_MAP = {
30609
30853
  46: "hhhh:mm:ss",
30610
30854
  47: "hhhh:mm:ss",
30611
30855
  48: undefined,
30612
- 49: undefined,
30856
+ 49: PLAIN_TEXT_FORMAT,
30613
30857
  };
30614
30858
  /**
30615
30859
  * Mapping format index to format defined by default
@@ -31530,20 +31774,26 @@ function convertFigures(sheetData) {
31530
31774
  .filter(isDefined$1);
31531
31775
  }
31532
31776
  function convertFigure(figure, id, sheetData) {
31533
- const x1 = getColPosition(figure.anchors[0].col, sheetData) +
31534
- convertEMUToDotValue(figure.anchors[0].colOffset);
31535
- const x2 = getColPosition(figure.anchors[1].col, sheetData) +
31536
- convertEMUToDotValue(figure.anchors[1].colOffset);
31537
- const y1 = getRowPosition(figure.anchors[0].row, sheetData) +
31538
- convertEMUToDotValue(figure.anchors[0].rowOffset);
31539
- const y2 = getRowPosition(figure.anchors[1].row, sheetData) +
31540
- convertEMUToDotValue(figure.anchors[1].rowOffset);
31777
+ let x1, y1;
31778
+ let height, width;
31779
+ if (figure.anchors.length === 1) {
31780
+ // one cell anchor
31781
+ ({ x: x1, y: y1 } = getPositionFromAnchor(figure.anchors[0], sheetData));
31782
+ width = convertEMUToDotValue(figure.figureSize.cx);
31783
+ height = convertEMUToDotValue(figure.figureSize.cy);
31784
+ }
31785
+ else {
31786
+ ({ x: x1, y: y1 } = getPositionFromAnchor(figure.anchors[0], sheetData));
31787
+ const { x: x2, y: y2 } = getPositionFromAnchor(figure.anchors[1], sheetData);
31788
+ width = x2 - x1;
31789
+ height = y2 - y1;
31790
+ }
31541
31791
  const figureData = { id, x: x1, y: y1 };
31542
31792
  if (isChartData(figure.data)) {
31543
31793
  return {
31544
31794
  ...figureData,
31545
- width: x2 - x1,
31546
- height: y2 - y1,
31795
+ width,
31796
+ height,
31547
31797
  tag: "chart",
31548
31798
  data: convertChartData(figure.data),
31549
31799
  };
@@ -31609,6 +31859,12 @@ function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
31609
31859
  const dataXC = zoneToXc(zone);
31610
31860
  return getFullReference(sheetName, dataXC);
31611
31861
  }
31862
+ function getPositionFromAnchor(anchor, sheetData) {
31863
+ return {
31864
+ x: getColPosition(anchor.col, sheetData) + convertEMUToDotValue(anchor.colOffset),
31865
+ y: getRowPosition(anchor.row, sheetData) + convertEMUToDotValue(anchor.rowOffset),
31866
+ };
31867
+ }
31612
31868
 
31613
31869
  /**
31614
31870
  * Match external reference (ex. '[1]Sheet 3'!$B$4)
@@ -32732,27 +32988,50 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
32732
32988
  }
32733
32989
  }
32734
32990
 
32991
+ const ONE_CELL_ANCHOR = "oneCellAnchor";
32992
+ const TWO_CELL_ANCHOR = "twoCellAnchor";
32735
32993
  class XlsxFigureExtractor extends XlsxBaseExtractor {
32736
32994
  extractFigures() {
32737
32995
  return this.mapOnElements({ parent: this.rootFile.file.xml, query: "xdr:wsDr", children: true }, (figureElement) => {
32738
32996
  const anchorType = removeTagEscapedNamespaces(figureElement.tagName);
32739
- if (anchorType !== "twoCellAnchor") {
32740
- throw new Error("Only twoCellAnchor are supported for xlsx drawings.");
32741
- }
32997
+ const anchors = this.extractFigureAnchorsByType(figureElement, anchorType);
32742
32998
  const chartElement = this.querySelector(figureElement, "c:chart");
32743
32999
  const imageElement = this.querySelector(figureElement, "a:blip");
32744
33000
  if (!chartElement && !imageElement) {
32745
33001
  throw new Error("Only chart and image figures are currently supported.");
32746
33002
  }
32747
33003
  return {
32748
- anchors: [
32749
- this.extractFigureAnchor("xdr:from", figureElement),
32750
- this.extractFigureAnchor("xdr:to", figureElement),
32751
- ],
33004
+ anchors,
32752
33005
  data: chartElement ? this.extractChart(chartElement) : this.extractImage(figureElement),
33006
+ figureSize: anchorType === ONE_CELL_ANCHOR
33007
+ ? this.extractFigureSizeFromSizeTag(figureElement, "xdr:ext")
33008
+ : undefined,
32753
33009
  };
32754
33010
  });
32755
33011
  }
33012
+ extractFigureAnchorsByType(figureElement, anchorType) {
33013
+ switch (anchorType) {
33014
+ case ONE_CELL_ANCHOR:
33015
+ return [this.extractFigureAnchor("xdr:from", figureElement)];
33016
+ case TWO_CELL_ANCHOR:
33017
+ return [
33018
+ this.extractFigureAnchor("xdr:from", figureElement),
33019
+ this.extractFigureAnchor("xdr:to", figureElement),
33020
+ ];
33021
+ default:
33022
+ throw new Error(`${anchorType} is not supported for xlsx drawings. `);
33023
+ }
33024
+ }
33025
+ extractFigureSizeFromSizeTag(figureElement, sizeTag) {
33026
+ const sizeElement = this.querySelector(figureElement, sizeTag);
33027
+ if (!sizeElement) {
33028
+ throw new Error(`Missing size element '${sizeTag}'`);
33029
+ }
33030
+ return {
33031
+ cx: this.extractAttr(sizeElement, "cx", { required: true }).asNum(),
33032
+ cy: this.extractAttr(sizeElement, "cy", { required: true }).asNum(),
33033
+ };
33034
+ }
32756
33035
  extractFigureAnchor(anchorTag, figureElement) {
32757
33036
  const anchor = this.querySelector(figureElement, anchorTag);
32758
33037
  if (!anchor) {
@@ -32781,15 +33060,15 @@ class XlsxFigureExtractor extends XlsxBaseExtractor {
32781
33060
  if (!image) {
32782
33061
  throw new Error("Unable to extract image");
32783
33062
  }
32784
- const shapePropertyElement = this.querySelector(figureElement, "a:xfrm");
32785
33063
  const extension = image.fileName.split(".").at(-1);
33064
+ const anchorType = removeTagEscapedNamespaces(figureElement.tagName);
33065
+ const sizeElement = anchorType === TWO_CELL_ANCHOR ? this.querySelector(figureElement, "a:xfrm") : figureElement;
33066
+ const sizeTag = anchorType === TWO_CELL_ANCHOR ? "a:ext" : "xdr:ext";
33067
+ const size = this.extractFigureSizeFromSizeTag(sizeElement, sizeTag);
32786
33068
  return {
32787
33069
  imageSrc: image.imageSrc,
32788
33070
  mimetype: extension ? IMAGE_EXTENSION_TO_MIMETYPE_MAPPING[extension] : undefined,
32789
- size: {
32790
- cx: this.extractChildAttr(shapePropertyElement, "a:ext", "cx", { required: true }).asNum(),
32791
- cy: this.extractChildAttr(shapePropertyElement, "a:ext", "cy", { required: true }).asNum(),
32792
- },
33071
+ size,
32793
33072
  };
32794
33073
  }
32795
33074
  }
@@ -34742,7 +35021,7 @@ class BordersPlugin extends CorePlugin {
34742
35021
  */
34743
35022
  function getBorderId(border) {
34744
35023
  for (let [key, value] of Object.entries(borders)) {
34745
- if (stringify(value) === stringify(border)) {
35024
+ if (deepEquals(value, border)) {
34746
35025
  return parseInt(key, 10);
34747
35026
  }
34748
35027
  }
@@ -35913,7 +36192,9 @@ class CellPlugin extends CorePlugin {
35913
36192
  }
35914
36193
  createLiteralCell(id, content, format, style) {
35915
36194
  const locale = this.getters.getLocale();
35916
- content = parseLiteral(content, locale).toString();
36195
+ if (format !== PLAIN_TEXT_FORMAT) {
36196
+ content = toString(parseLiteral(content, locale));
36197
+ }
35917
36198
  return {
35918
36199
  id,
35919
36200
  content,
@@ -40060,56 +40341,758 @@ class CompilationParametersBuilder {
40060
40341
  }
40061
40342
  }
40062
40343
 
40344
+ function quickselect(arr, k, left, right, compare) {
40345
+ quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare);
40346
+ }
40347
+
40348
+ function quickselectStep(arr, k, left, right, compare) {
40349
+
40350
+ while (right > left) {
40351
+ if (right - left > 600) {
40352
+ var n = right - left + 1;
40353
+ var m = k - left + 1;
40354
+ var z = Math.log(n);
40355
+ var s = 0.5 * Math.exp(2 * z / 3);
40356
+ var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
40357
+ var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
40358
+ var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
40359
+ quickselectStep(arr, k, newLeft, newRight, compare);
40360
+ }
40361
+
40362
+ var t = arr[k];
40363
+ var i = left;
40364
+ var j = right;
40365
+
40366
+ swap(arr, left, k);
40367
+ if (compare(arr[right], t) > 0) swap(arr, left, right);
40368
+
40369
+ while (i < j) {
40370
+ swap(arr, i, j);
40371
+ i++;
40372
+ j--;
40373
+ while (compare(arr[i], t) < 0) i++;
40374
+ while (compare(arr[j], t) > 0) j--;
40375
+ }
40376
+
40377
+ if (compare(arr[left], t) === 0) swap(arr, left, j);
40378
+ else {
40379
+ j++;
40380
+ swap(arr, j, right);
40381
+ }
40382
+
40383
+ if (j <= k) left = j + 1;
40384
+ if (k <= j) right = j - 1;
40385
+ }
40386
+ }
40387
+
40388
+ function swap(arr, i, j) {
40389
+ var tmp = arr[i];
40390
+ arr[i] = arr[j];
40391
+ arr[j] = tmp;
40392
+ }
40393
+
40394
+ function defaultCompare(a, b) {
40395
+ return a < b ? -1 : a > b ? 1 : 0;
40396
+ }
40397
+
40398
+ class RBush {
40399
+ constructor(maxEntries = 9) {
40400
+ // max entries in a node is 9 by default; min node fill is 40% for best performance
40401
+ this._maxEntries = Math.max(4, maxEntries);
40402
+ this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
40403
+ this.clear();
40404
+ }
40405
+
40406
+ all() {
40407
+ return this._all(this.data, []);
40408
+ }
40409
+
40410
+ search(bbox) {
40411
+ let node = this.data;
40412
+ const result = [];
40413
+
40414
+ if (!intersects(bbox, node)) return result;
40415
+
40416
+ const toBBox = this.toBBox;
40417
+ const nodesToSearch = [];
40418
+
40419
+ while (node) {
40420
+ for (let i = 0; i < node.children.length; i++) {
40421
+ const child = node.children[i];
40422
+ const childBBox = node.leaf ? toBBox(child) : child;
40423
+
40424
+ if (intersects(bbox, childBBox)) {
40425
+ if (node.leaf) result.push(child);
40426
+ else if (contains(bbox, childBBox)) this._all(child, result);
40427
+ else nodesToSearch.push(child);
40428
+ }
40429
+ }
40430
+ node = nodesToSearch.pop();
40431
+ }
40432
+
40433
+ return result;
40434
+ }
40435
+
40436
+ collides(bbox) {
40437
+ let node = this.data;
40438
+
40439
+ if (!intersects(bbox, node)) return false;
40440
+
40441
+ const nodesToSearch = [];
40442
+ while (node) {
40443
+ for (let i = 0; i < node.children.length; i++) {
40444
+ const child = node.children[i];
40445
+ const childBBox = node.leaf ? this.toBBox(child) : child;
40446
+
40447
+ if (intersects(bbox, childBBox)) {
40448
+ if (node.leaf || contains(bbox, childBBox)) return true;
40449
+ nodesToSearch.push(child);
40450
+ }
40451
+ }
40452
+ node = nodesToSearch.pop();
40453
+ }
40454
+
40455
+ return false;
40456
+ }
40457
+
40458
+ load(data) {
40459
+ if (!(data && data.length)) return this;
40460
+
40461
+ if (data.length < this._minEntries) {
40462
+ for (let i = 0; i < data.length; i++) {
40463
+ this.insert(data[i]);
40464
+ }
40465
+ return this;
40466
+ }
40467
+
40468
+ // recursively build the tree with the given data from scratch using OMT algorithm
40469
+ let node = this._build(data.slice(), 0, data.length - 1, 0);
40470
+
40471
+ if (!this.data.children.length) {
40472
+ // save as is if tree is empty
40473
+ this.data = node;
40474
+
40475
+ } else if (this.data.height === node.height) {
40476
+ // split root if trees have the same height
40477
+ this._splitRoot(this.data, node);
40478
+
40479
+ } else {
40480
+ if (this.data.height < node.height) {
40481
+ // swap trees if inserted one is bigger
40482
+ const tmpNode = this.data;
40483
+ this.data = node;
40484
+ node = tmpNode;
40485
+ }
40486
+
40487
+ // insert the small tree into the large tree at appropriate level
40488
+ this._insert(node, this.data.height - node.height - 1, true);
40489
+ }
40490
+
40491
+ return this;
40492
+ }
40493
+
40494
+ insert(item) {
40495
+ if (item) this._insert(item, this.data.height - 1);
40496
+ return this;
40497
+ }
40498
+
40499
+ clear() {
40500
+ this.data = createNode([]);
40501
+ return this;
40502
+ }
40503
+
40504
+ remove(item, equalsFn) {
40505
+ if (!item) return this;
40506
+
40507
+ let node = this.data;
40508
+ const bbox = this.toBBox(item);
40509
+ const path = [];
40510
+ const indexes = [];
40511
+ let i, parent, goingUp;
40512
+
40513
+ // depth-first iterative tree traversal
40514
+ while (node || path.length) {
40515
+
40516
+ if (!node) { // go up
40517
+ node = path.pop();
40518
+ parent = path[path.length - 1];
40519
+ i = indexes.pop();
40520
+ goingUp = true;
40521
+ }
40522
+
40523
+ if (node.leaf) { // check current node
40524
+ const index = findItem(item, node.children, equalsFn);
40525
+
40526
+ if (index !== -1) {
40527
+ // item found, remove the item and condense tree upwards
40528
+ node.children.splice(index, 1);
40529
+ path.push(node);
40530
+ this._condense(path);
40531
+ return this;
40532
+ }
40533
+ }
40534
+
40535
+ if (!goingUp && !node.leaf && contains(node, bbox)) { // go down
40536
+ path.push(node);
40537
+ indexes.push(i);
40538
+ i = 0;
40539
+ parent = node;
40540
+ node = node.children[0];
40541
+
40542
+ } else if (parent) { // go right
40543
+ i++;
40544
+ node = parent.children[i];
40545
+ goingUp = false;
40546
+
40547
+ } else node = null; // nothing found
40548
+ }
40549
+
40550
+ return this;
40551
+ }
40552
+
40553
+ toBBox(item) { return item; }
40554
+
40555
+ compareMinX(a, b) { return a.minX - b.minX; }
40556
+ compareMinY(a, b) { return a.minY - b.minY; }
40557
+
40558
+ toJSON() { return this.data; }
40559
+
40560
+ fromJSON(data) {
40561
+ this.data = data;
40562
+ return this;
40563
+ }
40564
+
40565
+ _all(node, result) {
40566
+ const nodesToSearch = [];
40567
+ while (node) {
40568
+ if (node.leaf) result.push(...node.children);
40569
+ else nodesToSearch.push(...node.children);
40570
+
40571
+ node = nodesToSearch.pop();
40572
+ }
40573
+ return result;
40574
+ }
40575
+
40576
+ _build(items, left, right, height) {
40577
+
40578
+ const N = right - left + 1;
40579
+ let M = this._maxEntries;
40580
+ let node;
40581
+
40582
+ if (N <= M) {
40583
+ // reached leaf level; return leaf
40584
+ node = createNode(items.slice(left, right + 1));
40585
+ calcBBox(node, this.toBBox);
40586
+ return node;
40587
+ }
40588
+
40589
+ if (!height) {
40590
+ // target height of the bulk-loaded tree
40591
+ height = Math.ceil(Math.log(N) / Math.log(M));
40592
+
40593
+ // target number of root entries to maximize storage utilization
40594
+ M = Math.ceil(N / Math.pow(M, height - 1));
40595
+ }
40596
+
40597
+ node = createNode([]);
40598
+ node.leaf = false;
40599
+ node.height = height;
40600
+
40601
+ // split the items into M mostly square tiles
40602
+
40603
+ const N2 = Math.ceil(N / M);
40604
+ const N1 = N2 * Math.ceil(Math.sqrt(M));
40605
+
40606
+ multiSelect(items, left, right, N1, this.compareMinX);
40607
+
40608
+ for (let i = left; i <= right; i += N1) {
40609
+
40610
+ const right2 = Math.min(i + N1 - 1, right);
40611
+
40612
+ multiSelect(items, i, right2, N2, this.compareMinY);
40613
+
40614
+ for (let j = i; j <= right2; j += N2) {
40615
+
40616
+ const right3 = Math.min(j + N2 - 1, right2);
40617
+
40618
+ // pack each entry recursively
40619
+ node.children.push(this._build(items, j, right3, height - 1));
40620
+ }
40621
+ }
40622
+
40623
+ calcBBox(node, this.toBBox);
40624
+
40625
+ return node;
40626
+ }
40627
+
40628
+ _chooseSubtree(bbox, node, level, path) {
40629
+ while (true) {
40630
+ path.push(node);
40631
+
40632
+ if (node.leaf || path.length - 1 === level) break;
40633
+
40634
+ let minArea = Infinity;
40635
+ let minEnlargement = Infinity;
40636
+ let targetNode;
40637
+
40638
+ for (let i = 0; i < node.children.length; i++) {
40639
+ const child = node.children[i];
40640
+ const area = bboxArea(child);
40641
+ const enlargement = enlargedArea(bbox, child) - area;
40642
+
40643
+ // choose entry with the least area enlargement
40644
+ if (enlargement < minEnlargement) {
40645
+ minEnlargement = enlargement;
40646
+ minArea = area < minArea ? area : minArea;
40647
+ targetNode = child;
40648
+
40649
+ } else if (enlargement === minEnlargement) {
40650
+ // otherwise choose one with the smallest area
40651
+ if (area < minArea) {
40652
+ minArea = area;
40653
+ targetNode = child;
40654
+ }
40655
+ }
40656
+ }
40657
+
40658
+ node = targetNode || node.children[0];
40659
+ }
40660
+
40661
+ return node;
40662
+ }
40663
+
40664
+ _insert(item, level, isNode) {
40665
+ const bbox = isNode ? item : this.toBBox(item);
40666
+ const insertPath = [];
40667
+
40668
+ // find the best node for accommodating the item, saving all nodes along the path too
40669
+ const node = this._chooseSubtree(bbox, this.data, level, insertPath);
40670
+
40671
+ // put the item into the node
40672
+ node.children.push(item);
40673
+ extend(node, bbox);
40674
+
40675
+ // split on node overflow; propagate upwards if necessary
40676
+ while (level >= 0) {
40677
+ if (insertPath[level].children.length > this._maxEntries) {
40678
+ this._split(insertPath, level);
40679
+ level--;
40680
+ } else break;
40681
+ }
40682
+
40683
+ // adjust bboxes along the insertion path
40684
+ this._adjustParentBBoxes(bbox, insertPath, level);
40685
+ }
40686
+
40687
+ // split overflowed node into two
40688
+ _split(insertPath, level) {
40689
+ const node = insertPath[level];
40690
+ const M = node.children.length;
40691
+ const m = this._minEntries;
40692
+
40693
+ this._chooseSplitAxis(node, m, M);
40694
+
40695
+ const splitIndex = this._chooseSplitIndex(node, m, M);
40696
+
40697
+ const newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
40698
+ newNode.height = node.height;
40699
+ newNode.leaf = node.leaf;
40700
+
40701
+ calcBBox(node, this.toBBox);
40702
+ calcBBox(newNode, this.toBBox);
40703
+
40704
+ if (level) insertPath[level - 1].children.push(newNode);
40705
+ else this._splitRoot(node, newNode);
40706
+ }
40707
+
40708
+ _splitRoot(node, newNode) {
40709
+ // split root node
40710
+ this.data = createNode([node, newNode]);
40711
+ this.data.height = node.height + 1;
40712
+ this.data.leaf = false;
40713
+ calcBBox(this.data, this.toBBox);
40714
+ }
40715
+
40716
+ _chooseSplitIndex(node, m, M) {
40717
+ let index;
40718
+ let minOverlap = Infinity;
40719
+ let minArea = Infinity;
40720
+
40721
+ for (let i = m; i <= M - m; i++) {
40722
+ const bbox1 = distBBox(node, 0, i, this.toBBox);
40723
+ const bbox2 = distBBox(node, i, M, this.toBBox);
40724
+
40725
+ const overlap = intersectionArea(bbox1, bbox2);
40726
+ const area = bboxArea(bbox1) + bboxArea(bbox2);
40727
+
40728
+ // choose distribution with minimum overlap
40729
+ if (overlap < minOverlap) {
40730
+ minOverlap = overlap;
40731
+ index = i;
40732
+
40733
+ minArea = area < minArea ? area : minArea;
40734
+
40735
+ } else if (overlap === minOverlap) {
40736
+ // otherwise choose distribution with minimum area
40737
+ if (area < minArea) {
40738
+ minArea = area;
40739
+ index = i;
40740
+ }
40741
+ }
40742
+ }
40743
+
40744
+ return index || M - m;
40745
+ }
40746
+
40747
+ // sorts node children by the best axis for split
40748
+ _chooseSplitAxis(node, m, M) {
40749
+ const compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
40750
+ const compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
40751
+ const xMargin = this._allDistMargin(node, m, M, compareMinX);
40752
+ const yMargin = this._allDistMargin(node, m, M, compareMinY);
40753
+
40754
+ // if total distributions margin value is minimal for x, sort by minX,
40755
+ // otherwise it's already sorted by minY
40756
+ if (xMargin < yMargin) node.children.sort(compareMinX);
40757
+ }
40758
+
40759
+ // total margin of all possible split distributions where each node is at least m full
40760
+ _allDistMargin(node, m, M, compare) {
40761
+ node.children.sort(compare);
40762
+
40763
+ const toBBox = this.toBBox;
40764
+ const leftBBox = distBBox(node, 0, m, toBBox);
40765
+ const rightBBox = distBBox(node, M - m, M, toBBox);
40766
+ let margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
40767
+
40768
+ for (let i = m; i < M - m; i++) {
40769
+ const child = node.children[i];
40770
+ extend(leftBBox, node.leaf ? toBBox(child) : child);
40771
+ margin += bboxMargin(leftBBox);
40772
+ }
40773
+
40774
+ for (let i = M - m - 1; i >= m; i--) {
40775
+ const child = node.children[i];
40776
+ extend(rightBBox, node.leaf ? toBBox(child) : child);
40777
+ margin += bboxMargin(rightBBox);
40778
+ }
40779
+
40780
+ return margin;
40781
+ }
40782
+
40783
+ _adjustParentBBoxes(bbox, path, level) {
40784
+ // adjust bboxes along the given tree path
40785
+ for (let i = level; i >= 0; i--) {
40786
+ extend(path[i], bbox);
40787
+ }
40788
+ }
40789
+
40790
+ _condense(path) {
40791
+ // go through the path, removing empty nodes and updating bboxes
40792
+ for (let i = path.length - 1, siblings; i >= 0; i--) {
40793
+ if (path[i].children.length === 0) {
40794
+ if (i > 0) {
40795
+ siblings = path[i - 1].children;
40796
+ siblings.splice(siblings.indexOf(path[i]), 1);
40797
+
40798
+ } else this.clear();
40799
+
40800
+ } else calcBBox(path[i], this.toBBox);
40801
+ }
40802
+ }
40803
+ }
40804
+
40805
+ function findItem(item, items, equalsFn) {
40806
+ if (!equalsFn) return items.indexOf(item);
40807
+
40808
+ for (let i = 0; i < items.length; i++) {
40809
+ if (equalsFn(item, items[i])) return i;
40810
+ }
40811
+ return -1;
40812
+ }
40813
+
40814
+ // calculate node's bbox from bboxes of its children
40815
+ function calcBBox(node, toBBox) {
40816
+ distBBox(node, 0, node.children.length, toBBox, node);
40817
+ }
40818
+
40819
+ // min bounding rectangle of node children from k to p-1
40820
+ function distBBox(node, k, p, toBBox, destNode) {
40821
+ if (!destNode) destNode = createNode(null);
40822
+ destNode.minX = Infinity;
40823
+ destNode.minY = Infinity;
40824
+ destNode.maxX = -Infinity;
40825
+ destNode.maxY = -Infinity;
40826
+
40827
+ for (let i = k; i < p; i++) {
40828
+ const child = node.children[i];
40829
+ extend(destNode, node.leaf ? toBBox(child) : child);
40830
+ }
40831
+
40832
+ return destNode;
40833
+ }
40834
+
40835
+ function extend(a, b) {
40836
+ a.minX = Math.min(a.minX, b.minX);
40837
+ a.minY = Math.min(a.minY, b.minY);
40838
+ a.maxX = Math.max(a.maxX, b.maxX);
40839
+ a.maxY = Math.max(a.maxY, b.maxY);
40840
+ return a;
40841
+ }
40842
+
40843
+ function compareNodeMinX(a, b) { return a.minX - b.minX; }
40844
+ function compareNodeMinY(a, b) { return a.minY - b.minY; }
40845
+
40846
+ function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); }
40847
+ function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
40848
+
40849
+ function enlargedArea(a, b) {
40850
+ return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
40851
+ (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
40852
+ }
40853
+
40854
+ function intersectionArea(a, b) {
40855
+ const minX = Math.max(a.minX, b.minX);
40856
+ const minY = Math.max(a.minY, b.minY);
40857
+ const maxX = Math.min(a.maxX, b.maxX);
40858
+ const maxY = Math.min(a.maxY, b.maxY);
40859
+
40860
+ return Math.max(0, maxX - minX) *
40861
+ Math.max(0, maxY - minY);
40862
+ }
40863
+
40864
+ function contains(a, b) {
40865
+ return a.minX <= b.minX &&
40866
+ a.minY <= b.minY &&
40867
+ b.maxX <= a.maxX &&
40868
+ b.maxY <= a.maxY;
40869
+ }
40870
+
40871
+ function intersects(a, b) {
40872
+ return b.minX <= a.maxX &&
40873
+ b.minY <= a.maxY &&
40874
+ b.maxX >= a.minX &&
40875
+ b.maxY >= a.minY;
40876
+ }
40877
+
40878
+ function createNode(children) {
40879
+ return {
40880
+ children,
40881
+ height: 1,
40882
+ leaf: true,
40883
+ minX: Infinity,
40884
+ minY: Infinity,
40885
+ maxX: -Infinity,
40886
+ maxY: -Infinity
40887
+ };
40888
+ }
40889
+
40890
+ // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
40891
+ // combines selection algorithm with binary divide & conquer approach
40892
+
40893
+ function multiSelect(arr, left, right, n, compare) {
40894
+ const stack = [left, right];
40895
+
40896
+ while (stack.length) {
40897
+ right = stack.pop();
40898
+ left = stack.pop();
40899
+
40900
+ if (right - left <= n) continue;
40901
+
40902
+ const mid = left + Math.ceil((right - left) / n / 2) * n;
40903
+ quickselect(arr, mid, left, right, compare);
40904
+
40905
+ stack.push(left, mid, mid, right);
40906
+ }
40907
+ }
40908
+
40063
40909
  /**
40064
- * This class is an implementation of a dependency Graph.
40910
+ * R-Tree Data Structure
40911
+ *
40912
+ * R-Tree is a spatial data structure used for efficient indexing and querying
40913
+ * of multi-dimensional objects, particularly in geometric and spatial applications.
40914
+ *
40915
+ * It organizes objects into a tree hierarchy, grouping nearby objects together
40916
+ * in bounding boxes. Each node in the tree represents a bounding box that
40917
+ * contains its child nodes or leaf objects. This hierarchical structure allows
40918
+ * for faster spatial queries.
40919
+ *
40920
+ * @see https://en.wikipedia.org/wiki/R-tree
40921
+ *
40922
+ * Consider a 2D Space with four zones: A, B, C, D
40923
+ * +--------------------------+
40924
+ * | |
40925
+ * | +---+ +-------+ |
40926
+ * | | A | | B | |
40927
+ * | +---+ +-------+ |
40928
+ * | |
40929
+ * | |
40930
+ * | +---+ |
40931
+ * | | C | |
40932
+ * | +---+ |
40933
+ * | +-----------+ |
40934
+ * | | D | |
40935
+ * | +-----------+ |
40936
+ * | |
40937
+ * +--------------------------+
40938
+ *
40939
+ * It groups together zones that are spatially close into a minimum bounding box.
40940
+ * For example, A and B are grouped together in rectangle R1, and C and D are grouped
40941
+ * in R2.
40942
+ *
40943
+ * R0
40944
+ * +--------------------------+
40945
+ * | R1 |
40946
+ * | +-----------------+ |
40947
+ * | | A | | B | |
40948
+ * | +-----------------+ |
40949
+ * | |
40950
+ * | R2 |
40951
+ * | +---+---+---+ |
40952
+ * | | | C | | |
40953
+ * | | +---+ | |
40954
+ * | +-----------+ |
40955
+ * | | D | |
40956
+ * | +-----------+ |
40957
+ * | |
40958
+ * +--------------------------+
40959
+ *
40960
+ * The tree would look like this:
40961
+ * R0
40962
+ * / \
40963
+ * / \
40964
+ * R1 R2
40965
+ * | |
40966
+ * A,B C,D
40967
+
40968
+ * Choosing how to group the zones is crucial for the performance of the tree.
40969
+ * Key considerations include avoiding excessive empty space coverage and minimizing overlap
40970
+ * to reduce the number of subtrees processed during searches.
40971
+ *
40972
+ * Various heuristics exist for determining the optimal grouping strategy, such as "least enlargement"
40973
+ * which prioritizes grouping nodes resulting in the smallest increase in bounding box size. In cases where
40974
+ * the choice cannot be made based on this criterion due to the same enlargement for different groupings,
40975
+ * we then evaluate "least area," aiming to minimize the overall area of bounding boxes.
40976
+ *
40977
+ * This implementation is tailored for spreadsheet use, indexing objects associated
40978
+ * with a zone and a sheet.
40979
+ *
40980
+ * It uses the RBush library under the hood. One 2D RBush R-tree per sheet.
40981
+ * @see https://github.com/mourner/rbush
40982
+ */
40983
+ class SpreadsheetRTree {
40984
+ /**
40985
+ * One 2D R-tree per sheet
40986
+ */
40987
+ rTrees = {};
40988
+ /**
40989
+ * Bulk-inserts the given items into the tree. Bulk insertion is usually ~2-3 times
40990
+ * faster than inserting items one by one. After bulk loading (bulk insertion into
40991
+ * an empty tree), subsequent query performance is also ~20-30% better.
40992
+ */
40993
+ constructor(items = []) {
40994
+ const rangesPerSheet = {};
40995
+ for (const item of items) {
40996
+ const sheetId = item.boundingBox.sheetId;
40997
+ if (!rangesPerSheet[sheetId]) {
40998
+ rangesPerSheet[sheetId] = [];
40999
+ }
41000
+ rangesPerSheet[sheetId].push(item);
41001
+ }
41002
+ for (const sheetId in rangesPerSheet) {
41003
+ this.rTrees[sheetId] = new ZoneRBush();
41004
+ this.rTrees[sheetId].load(rangesPerSheet[sheetId]); // bulk-insert
41005
+ }
41006
+ }
41007
+ insert(item) {
41008
+ const sheetId = item.boundingBox.sheetId;
41009
+ if (!this.rTrees[sheetId]) {
41010
+ this.rTrees[sheetId] = new ZoneRBush();
41011
+ }
41012
+ this.rTrees[sheetId].insert(item);
41013
+ }
41014
+ search({ zone, sheetId }) {
41015
+ if (!this.rTrees[sheetId]) {
41016
+ return [];
41017
+ }
41018
+ return this.rTrees[sheetId].search({
41019
+ minX: zone.left,
41020
+ minY: zone.top,
41021
+ maxX: zone.right,
41022
+ maxY: zone.bottom,
41023
+ });
41024
+ }
41025
+ remove(item) {
41026
+ const sheetId = item.boundingBox.sheetId;
41027
+ if (!this.rTrees[sheetId]) {
41028
+ return;
41029
+ }
41030
+ this.rTrees[sheetId].remove(item, deepEquals);
41031
+ }
41032
+ }
41033
+ /**
41034
+ * RBush extension to use zones as bounding boxes
41035
+ */
41036
+ class ZoneRBush extends RBush {
41037
+ toBBox({ boundingBox }) {
41038
+ const zone = boundingBox.zone;
41039
+ return {
41040
+ minX: zone.left,
41041
+ minY: zone.top,
41042
+ maxX: zone.right,
41043
+ maxY: zone.bottom,
41044
+ };
41045
+ }
41046
+ compareMinX(a, b) {
41047
+ return a.boundingBox.zone.left - b.boundingBox.zone.left;
41048
+ }
41049
+ compareMinY(a, b) {
41050
+ return a.boundingBox.zone.top - b.boundingBox.zone.top;
41051
+ }
41052
+ }
41053
+
41054
+ /**
41055
+ * Implementation of a dependency Graph.
40065
41056
  * The graph is used to evaluate the cells in the correct
40066
41057
  * order, and should be updated each time a cell's content is modified
40067
41058
  *
41059
+ * It uses an R-Tree data structure to efficiently find dependent cells.
40068
41060
  */
40069
41061
  class FormulaDependencyGraph {
40070
- /**
40071
- * Internal structure:
40072
- * - key: a cell position (encoded as an integer)
40073
- * - value: a set of cell positions that depends on the key
40074
- *
40075
- * Given
40076
- * - A1:"= B1 + SQRT(B2)"
40077
- * - C1:"= B1";
40078
- * - C2:"= C1"
40079
- *
40080
- * we will have something like:
40081
- * - B1 ---> (A1, C1) meaning A1 and C1 depends on B1
40082
- * - B2 ---> (A1) meaning A1 depends on B2
40083
- * - C1 ---> (C2) meaning C2 depends on C1
40084
- */
40085
- inverseDependencies = new Map();
41062
+ encoder;
40086
41063
  dependencies = new Map();
41064
+ rTree;
41065
+ constructor(encoder, data = []) {
41066
+ this.encoder = encoder;
41067
+ this.rTree = new SpreadsheetRTree(data);
41068
+ }
40087
41069
  removeAllDependencies(formulaPositionId) {
40088
- const dependencies = this.dependencies.get(formulaPositionId);
40089
- if (!dependencies) {
41070
+ const ranges = this.dependencies.get(formulaPositionId);
41071
+ if (!ranges) {
40090
41072
  return;
40091
41073
  }
40092
- for (const dependency of dependencies) {
40093
- this.inverseDependencies.get(dependency)?.delete(formulaPositionId);
41074
+ for (const range of ranges) {
41075
+ this.rTree.remove(range);
40094
41076
  }
40095
41077
  this.dependencies.delete(formulaPositionId);
40096
41078
  }
40097
41079
  addDependencies(formulaPositionId, dependencies) {
40098
- for (const dependency of dependencies) {
40099
- const inverseDependencies = this.inverseDependencies.get(dependency);
40100
- if (inverseDependencies) {
40101
- inverseDependencies.add(formulaPositionId);
40102
- }
40103
- else {
40104
- this.inverseDependencies.set(dependency, new Set([formulaPositionId]));
40105
- }
41080
+ const rTreeItems = dependencies.map(({ sheetId, zone }) => ({
41081
+ data: formulaPositionId,
41082
+ boundingBox: {
41083
+ zone,
41084
+ sheetId,
41085
+ },
41086
+ }));
41087
+ for (const item of rTreeItems) {
41088
+ this.rTree.insert(item);
40106
41089
  }
40107
41090
  const existingDependencies = this.dependencies.get(formulaPositionId);
40108
41091
  if (existingDependencies) {
40109
- existingDependencies.push(...dependencies);
41092
+ existingDependencies.push(...rTreeItems);
40110
41093
  }
40111
41094
  else {
40112
- this.dependencies.set(formulaPositionId, dependencies);
41095
+ this.dependencies.set(formulaPositionId, rTreeItems);
40113
41096
  }
40114
41097
  }
40115
41098
  /**
@@ -40117,20 +41100,20 @@ class FormulaDependencyGraph {
40117
41100
  * in the correct order they should be evaluated.
40118
41101
  * This is called a topological ordering (excluding cycles)
40119
41102
  */
40120
- getCellsDependingOn(positionIds) {
41103
+ getCellsDependingOn(ranges) {
40121
41104
  const visited = new JetSet();
40122
- const queue = Array.from(positionIds).reverse();
41105
+ const queue = Array.from(ranges).reverse();
40123
41106
  while (queue.length > 0) {
40124
- const node = queue.pop();
40125
- visited.add(node);
40126
- const adjacentNodes = this.inverseDependencies.get(node) || new Set();
40127
- for (const adjacentNode of adjacentNodes) {
40128
- if (!visited.has(adjacentNode)) {
40129
- queue.push(adjacentNode);
41107
+ const range = queue.pop();
41108
+ visited.add(...this.encoder.encodeBoundingBox(range));
41109
+ const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
41110
+ for (const positionId of impactedPositionIds) {
41111
+ if (!visited.has(positionId)) {
41112
+ queue.push(this.encoder.decodeToBoundingBox(positionId));
40130
41113
  }
40131
41114
  }
40132
41115
  }
40133
- visited.delete(...positionIds);
41116
+ visited.delete(...ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
40134
41117
  return visited;
40135
41118
  }
40136
41119
  }
@@ -40218,9 +41201,9 @@ class Evaluator {
40218
41201
  context;
40219
41202
  getters;
40220
41203
  compilationParams;
40221
- positionEncoder = new PositionBitsEncoder();
41204
+ encoder = new PositionBitsEncoder();
40222
41205
  evaluatedCells = new Map();
40223
- formulaDependencies = lazy(new FormulaDependencyGraph());
41206
+ formulaDependencies = lazy(new FormulaDependencyGraph(this.encoder));
40224
41207
  blockedArrayFormulas = new Set();
40225
41208
  spreadingRelations = new SpreadingRelation();
40226
41209
  constructor(context, getters) {
@@ -40229,23 +41212,23 @@ class Evaluator {
40229
41212
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
40230
41213
  }
40231
41214
  getEvaluatedCell(position) {
40232
- return (this.evaluatedCells.get(this.encodePosition(position)) ||
41215
+ return (this.evaluatedCells.get(this.encoder.encode(position)) ||
40233
41216
  createEvaluatedCell("", { locale: this.getters.getLocale() }));
40234
41217
  }
40235
41218
  getSpreadPositionsOf(position) {
40236
- const positionId = this.encodePosition(position);
41219
+ const positionId = this.encoder.encode(position);
40237
41220
  if (!this.spreadingRelations.isArrayFormula(positionId)) {
40238
41221
  return [];
40239
41222
  }
40240
- return Array.from(this.spreadingRelations.getArrayResultPositionIds(positionId)).map(this.decodePosition.bind(this));
41223
+ return Array.from(this.spreadingRelations.getArrayResultPositionIds(positionId)).map((positionId) => this.encoder.decode(positionId));
40241
41224
  }
40242
41225
  getArrayFormulaSpreadingOn(position) {
40243
- const positionId = this.encodePosition(position);
41226
+ const positionId = this.encoder.encode(position);
40244
41227
  const formulaPosition = this.getArrayFormulaSpreadingOnId(positionId);
40245
- return formulaPosition !== undefined ? this.decodePosition(formulaPosition) : undefined;
41228
+ return formulaPosition !== undefined ? this.encoder.decode(formulaPosition) : undefined;
40246
41229
  }
40247
41230
  getEvaluatedPositions() {
40248
- return [...this.evaluatedCells.keys()].map(this.decodePosition.bind(this));
41231
+ return [...this.evaluatedCells.keys()].map((p) => this.encoder.decode(p));
40249
41232
  }
40250
41233
  getArrayFormulaSpreadingOnId(positionId) {
40251
41234
  if (!this.spreadingRelations.hasArrayFormulaResult(positionId)) {
@@ -40255,7 +41238,7 @@ class Evaluator {
40255
41238
  return Array.from(arrayFormulas).find((positionId) => !this.blockedArrayFormulas.has(positionId));
40256
41239
  }
40257
41240
  updateDependencies(position) {
40258
- const positionId = this.encodePosition(position);
41241
+ const positionId = this.encoder.encode(position);
40259
41242
  this.formulaDependencies().removeAllDependencies(positionId);
40260
41243
  const dependencies = this.getDirectDependencies(positionId);
40261
41244
  this.formulaDependencies().addDependencies(positionId, dependencies);
@@ -40265,12 +41248,12 @@ class Evaluator {
40265
41248
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
40266
41249
  }
40267
41250
  evaluateCells(positions) {
40268
- const cells = positions.map(this.encodePosition.bind(this));
41251
+ const cells = positions.map((p) => this.encoder.encode(p));
40269
41252
  const cellsToCompute = new JetSet(cells);
40270
- const arrayFormulas = this.getArrayFormulasImpactedByChangesOf(cells);
41253
+ const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
40271
41254
  cellsToCompute.add(...this.getCellsDependingOn(cells));
40272
- cellsToCompute.add(...arrayFormulas);
40273
- cellsToCompute.add(...this.getCellsDependingOn(arrayFormulas));
41255
+ cellsToCompute.add(...arrayFormulasPositionIds);
41256
+ cellsToCompute.add(...this.getCellsDependingOn(arrayFormulasPositionIds));
40274
41257
  this.evaluate(cellsToCompute);
40275
41258
  }
40276
41259
  getArrayFormulasImpactedByChangesOf(positionIds) {
@@ -40293,12 +41276,14 @@ class Evaluator {
40293
41276
  this.blockedArrayFormulas = new Set();
40294
41277
  this.spreadingRelations = new SpreadingRelation();
40295
41278
  this.formulaDependencies = lazy(() => {
40296
- const dependencyGraph = new FormulaDependencyGraph();
40297
- for (const positionId of this.getAllCells()) {
40298
- const dependencies = this.getDirectDependencies(positionId);
40299
- dependencyGraph.addDependencies(positionId, dependencies);
40300
- }
40301
- return dependencyGraph;
41279
+ const dependencies = [...this.getAllCells()].flatMap((positionId) => this.getDirectDependencies(positionId).map((range) => ({
41280
+ data: positionId,
41281
+ boundingBox: {
41282
+ zone: range.zone,
41283
+ sheetId: range.sheetId,
41284
+ },
41285
+ })));
41286
+ return new FormulaDependencyGraph(this.encoder, dependencies);
40302
41287
  });
40303
41288
  }
40304
41289
  evaluateAllCells() {
@@ -40320,7 +41305,7 @@ class Evaluator {
40320
41305
  for (const sheetId of this.getters.getSheetIds()) {
40321
41306
  const cellIds = this.getters.getCells(sheetId);
40322
41307
  for (const cellId in cellIds) {
40323
- positionIds.add(this.encodePosition(this.getters.getCellPosition(cellId)));
41308
+ positionIds.add(this.encoder.encode(this.getters.getCellPosition(cellId)));
40324
41309
  }
40325
41310
  }
40326
41311
  return positionIds;
@@ -40365,7 +41350,7 @@ class Evaluator {
40365
41350
  if (!this.blockedArrayFormulas.has(positionId)) {
40366
41351
  this.invalidateSpreading(positionId);
40367
41352
  }
40368
- const cellPosition = this.decodePosition(positionId);
41353
+ const cellPosition = this.encoder.decode(positionId);
40369
41354
  const cell = this.getters.getCell(cellPosition);
40370
41355
  if (cell === undefined) {
40371
41356
  return createEvaluatedCell("", { locale: this.getters.getLocale() });
@@ -40388,7 +41373,7 @@ class Evaluator {
40388
41373
  }
40389
41374
  }
40390
41375
  computeAndSave(position) {
40391
- const positionId = this.encodePosition(position);
41376
+ const positionId = this.encoder.encode(position);
40392
41377
  const evaluatedCell = this.computeCell(positionId);
40393
41378
  if (!this.evaluatedCells.has(positionId)) {
40394
41379
  this.setEvaluatedCell(positionId, evaluatedCell);
@@ -40443,15 +41428,15 @@ class Evaluator {
40443
41428
  throw new Error(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
40444
41429
  }
40445
41430
  updateSpreadRelation({ sheetId, col, row, }) {
40446
- const arrayFormulaPositionId = this.encodePosition({ sheetId, col, row });
41431
+ const arrayFormulaPositionId = this.encoder.encode({ sheetId, col, row });
40447
41432
  return (i, j) => {
40448
41433
  const position = { sheetId, col: i + col, row: j + row };
40449
- const resultPositionId = this.encodePosition(position);
41434
+ const resultPositionId = this.encoder.encode(position);
40450
41435
  this.spreadingRelations.addRelation({ resultPositionId, arrayFormulaPositionId });
40451
41436
  };
40452
41437
  }
40453
41438
  checkCollision({ sheetId, col, row }) {
40454
- const formulaPositionId = this.encodePosition({ sheetId, col, row });
41439
+ const formulaPositionId = this.encoder.encode({ sheetId, col, row });
40455
41440
  return (i, j) => {
40456
41441
  const position = { sheetId: sheetId, col: i + col, row: j + row };
40457
41442
  const rawCell = this.getters.getCell(position);
@@ -40472,7 +41457,7 @@ class Evaluator {
40472
41457
  format: format || matrixResult[i][j]?.format,
40473
41458
  locale: this.getters.getLocale(),
40474
41459
  });
40475
- const positionId = this.encodePosition(position);
41460
+ const positionId = this.encoder.encode(position);
40476
41461
  this.setEvaluatedCell(positionId, evaluatedCell);
40477
41462
  // check if formula dependencies present in the spread zone
40478
41463
  // if so, they need to be recomputed
@@ -40504,29 +41489,17 @@ class Evaluator {
40504
41489
  if (!cell?.isFormula) {
40505
41490
  return [];
40506
41491
  }
40507
- const dependencies = [];
40508
- for (const range of cell.compiledFormula.dependencies) {
40509
- if (range.invalidSheetName || range.invalidXc) {
40510
- continue;
40511
- }
40512
- const sheetId = range.sheetId;
40513
- forEachPositionsInZone(range.zone, (col, row) => {
40514
- dependencies.push(this.encodePosition({ sheetId, col, row }));
40515
- });
40516
- }
40517
- return dependencies;
41492
+ return cell.compiledFormula.dependencies;
40518
41493
  }
40519
41494
  getCellsDependingOn(positionIds) {
40520
- return this.formulaDependencies().getCellsDependingOn(positionIds);
41495
+ const ranges = [];
41496
+ for (const positionId of positionIds) {
41497
+ ranges.push(this.encoder.decodeToBoundingBox(positionId));
41498
+ }
41499
+ return this.formulaDependencies().getCellsDependingOn(ranges);
40521
41500
  }
40522
41501
  getCell(positionId) {
40523
- return this.getters.getCell(this.decodePosition(positionId));
40524
- }
40525
- encodePosition(position) {
40526
- return this.positionEncoder.encode(position);
40527
- }
40528
- decodePosition(positionId) {
40529
- return this.positionEncoder.decode(positionId);
41502
+ return this.getters.getCell(this.encoder.decode(positionId));
40530
41503
  }
40531
41504
  }
40532
41505
  function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
@@ -40582,6 +41555,13 @@ class PositionBitsEncoder {
40582
41555
  encode({ sheetId, col, row }) {
40583
41556
  return (this.encodeSheet(sheetId) << 42n) | (BigInt(col) << 21n) | BigInt(row);
40584
41557
  }
41558
+ encodeBoundingBox({ sheetId, zone }) {
41559
+ const positions = [];
41560
+ forEachPositionsInZone(zone, (col, row) => {
41561
+ positions.push(this.encode({ sheetId, col, row }));
41562
+ });
41563
+ return positions;
41564
+ }
40585
41565
  decode(id) {
40586
41566
  // keep only the last 21 bits by AND-ing the bit sequence with 21 ones
40587
41567
  const row = Number(id & 2097151n);
@@ -40589,6 +41569,10 @@ class PositionBitsEncoder {
40589
41569
  const sheetId = this.decodeSheet(id >> 42n);
40590
41570
  return { sheetId, col, row };
40591
41571
  }
41572
+ decodeToBoundingBox(id) {
41573
+ const { sheetId, col, row } = this.decode(id);
41574
+ return { sheetId, zone: { left: col, top: row, right: col, bottom: row } };
41575
+ }
40592
41576
  encodeSheet(sheetId) {
40593
41577
  const sheetKey = this.sheetMapping[sheetId];
40594
41578
  if (sheetKey === undefined) {
@@ -40771,7 +41755,12 @@ class EvaluationPlugin extends UIPlugin {
40771
41755
  // Getters
40772
41756
  // ---------------------------------------------------------------------------
40773
41757
  evaluateFormula(sheetId, formulaString) {
40774
- return this.evaluator.evaluateFormula(sheetId, formulaString);
41758
+ try {
41759
+ return this.evaluator.evaluateFormula(sheetId, formulaString);
41760
+ }
41761
+ catch (error) {
41762
+ return error instanceof EvaluationError ? error.errorType : CellErrorType.GenericError;
41763
+ }
40775
41764
  }
40776
41765
  /**
40777
41766
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -41040,7 +42029,7 @@ class CustomColorsPlugin extends UIPlugin {
41040
42029
  }
41041
42030
 
41042
42031
  class EvaluationChartPlugin extends UIPlugin {
41043
- static getters = ["getChartRuntime", "getBackgroundOfSingleCellChart"];
42032
+ static getters = ["getChartRuntime", "getStyleOfSingleCellChart"];
41044
42033
  charts = {};
41045
42034
  createRuntimeChart = chartRuntimeFactory(this.getters);
41046
42035
  handle(cmd) {
@@ -41078,25 +42067,26 @@ class EvaluationChartPlugin extends UIPlugin {
41078
42067
  return this.charts[figureId];
41079
42068
  }
41080
42069
  /**
41081
- * Get the background color of a chart based on the color of the first cell of the main range
41082
- * of the chart. In order of priority, it will return :
41083
- *
41084
- * - the chart background color if one is defined
41085
- * - the fill color of the cell if one is defined
41086
- * - the fill color of the cell from conditional formats if one is defined
41087
- * - the default chart color if no other color is defined
42070
+ * Get the background and textColor of a chart based on the color of the first cell of the main range of the chart.
41088
42071
  */
41089
- getBackgroundOfSingleCellChart(chartBackground, mainRange) {
42072
+ getStyleOfSingleCellChart(chartBackground, mainRange) {
41090
42073
  if (chartBackground)
41091
- return chartBackground;
42074
+ return { background: chartBackground, fontColor: chartFontColor(chartBackground) };
41092
42075
  if (!mainRange) {
41093
- return BACKGROUND_CHART_COLOR;
42076
+ return {
42077
+ background: BACKGROUND_CHART_COLOR,
42078
+ fontColor: chartFontColor(BACKGROUND_CHART_COLOR),
42079
+ };
41094
42080
  }
41095
42081
  const col = mainRange.zone.left;
41096
42082
  const row = mainRange.zone.top;
41097
42083
  const sheetId = mainRange.sheetId;
41098
42084
  const style = this.getters.getCellComputedStyle({ sheetId, col, row });
41099
- return style.fillColor || BACKGROUND_CHART_COLOR;
42085
+ const background = style.fillColor || BACKGROUND_CHART_COLOR;
42086
+ return {
42087
+ background,
42088
+ fontColor: style.textColor || chartFontColor(background),
42089
+ };
41100
42090
  }
41101
42091
  exportForExcel(data) {
41102
42092
  for (const sheet of data.sheets) {
@@ -41207,45 +42197,40 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
41207
42197
  getComputedStyles(sheetId) {
41208
42198
  const computedStyle = {};
41209
42199
  for (let cf of this.getters.getConditionalFormats(sheetId).reverse()) {
41210
- try {
41211
- switch (cf.rule.type) {
41212
- case "ColorScaleRule":
41213
- for (let range of cf.ranges) {
41214
- this.applyColorScale(sheetId, range, cf.rule, computedStyle);
41215
- }
41216
- break;
41217
- case "CellIsRule":
41218
- const formulas = cf.rule.values.map((value) => value.startsWith("=") ? compile(value) : undefined);
41219
- for (let ref of cf.ranges) {
41220
- const zone = this.getters.getRangeFromSheetXC(sheetId, ref).zone;
41221
- for (let row = zone.top; row <= zone.bottom; row++) {
41222
- for (let col = zone.left; col <= zone.right; col++) {
41223
- const predicate = this.rulePredicate[cf.rule.type];
41224
- const target = { sheetId, col, row };
41225
- const values = cf.rule.values.map((value, i) => {
41226
- const compiledFormula = formulas[i];
41227
- if (compiledFormula) {
41228
- return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, {
41229
- ...compiledFormula,
41230
- dependencies: compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
41231
- });
41232
- }
41233
- return value;
41234
- });
41235
- if (predicate && predicate(target, { ...cf.rule, values })) {
41236
- if (!computedStyle[col])
41237
- computedStyle[col] = [];
41238
- // we must combine all the properties of all the CF rules applied to the given cell
41239
- computedStyle[col][row] = Object.assign(computedStyle[col]?.[row] || {}, cf.rule.style);
42200
+ switch (cf.rule.type) {
42201
+ case "ColorScaleRule":
42202
+ for (let range of cf.ranges) {
42203
+ this.applyColorScale(sheetId, range, cf.rule, computedStyle);
42204
+ }
42205
+ break;
42206
+ case "CellIsRule":
42207
+ const formulas = cf.rule.values.map((value) => value.startsWith("=") ? compile(value) : undefined);
42208
+ for (let ref of cf.ranges) {
42209
+ const zone = this.getters.getRangeFromSheetXC(sheetId, ref).zone;
42210
+ for (let row = zone.top; row <= zone.bottom; row++) {
42211
+ for (let col = zone.left; col <= zone.right; col++) {
42212
+ const predicate = this.rulePredicate[cf.rule.type];
42213
+ const target = { sheetId, col, row };
42214
+ const values = cf.rule.values.map((value, i) => {
42215
+ const compiledFormula = formulas[i];
42216
+ if (compiledFormula) {
42217
+ return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, {
42218
+ ...compiledFormula,
42219
+ dependencies: compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
42220
+ });
41240
42221
  }
42222
+ return value;
42223
+ });
42224
+ if (predicate && predicate(target, { ...cf.rule, values })) {
42225
+ if (!computedStyle[col])
42226
+ computedStyle[col] = [];
42227
+ // we must combine all the properties of all the CF rules applied to the given cell
42228
+ computedStyle[col][row] = Object.assign(computedStyle[col]?.[row] || {}, cf.rule.style);
41241
42229
  }
41242
42230
  }
41243
42231
  }
41244
- break;
41245
- }
41246
- }
41247
- catch (_) {
41248
- // we don't care about the errors within the evaluation of a rule
42232
+ }
42233
+ break;
41249
42234
  }
41250
42235
  }
41251
42236
  return computedStyle;
@@ -41856,11 +42841,6 @@ class AutofillPlugin extends UIPlugin {
41856
42841
  return "Success" /* CommandResult.Success */;
41857
42842
  }
41858
42843
  return "InvalidAutofillSelection" /* CommandResult.InvalidAutofillSelection */;
41859
- case "AUTOFILL_AUTO":
41860
- const zone = this.getters.getSelectedZone();
41861
- return zone.top === zone.bottom
41862
- ? "Success" /* CommandResult.Success */
41863
- : "CancelledForUnknownReason" /* CommandResult.CancelledForUnknownReason */;
41864
42844
  }
41865
42845
  return "Success" /* CommandResult.Success */;
41866
42846
  }
@@ -42017,7 +42997,7 @@ class AutofillPlugin extends UIPlugin {
42017
42997
  let row = zone.bottom;
42018
42998
  if (col > 0) {
42019
42999
  let leftPosition = { sheetId, col: col - 1, row };
42020
- while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty ||
43000
+ while (this.getters.getCorrespondingFormulaCell(leftPosition) ||
42021
43001
  this.getters.getCell(leftPosition)?.content) {
42022
43002
  row += 1;
42023
43003
  leftPosition = { sheetId, col: col - 1, row };
@@ -42027,7 +43007,7 @@ class AutofillPlugin extends UIPlugin {
42027
43007
  col = zone.right;
42028
43008
  if (col <= this.getters.getNumberCols(sheetId)) {
42029
43009
  let rightPosition = { sheetId, col: col + 1, row };
42030
- while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty ||
43010
+ while (this.getters.getCorrespondingFormulaCell(rightPosition) ||
42031
43011
  this.getters.getCell(rightPosition)?.content) {
42032
43012
  row += 1;
42033
43013
  rightPosition = { sheetId, col: col + 1, row };
@@ -43622,7 +44602,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
43622
44602
  isPasteAllowed(target, clipboardOption) {
43623
44603
  const sheetId = this.getters.getActiveSheetId();
43624
44604
  if (this.operation === "CUT" && clipboardOption?.pasteOption !== undefined) {
43625
- // cannot paste only format or only value if the previous operation is a CUT
44605
+ // cannot paste only format or as value if the previous operation is a CUT
43626
44606
  return "WrongPasteOption" /* CommandResult.WrongPasteOption */;
43627
44607
  }
43628
44608
  if (target.length > 1) {
@@ -43804,7 +44784,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
43804
44784
  // This condition is used to determine if we have to paste the CF or not.
43805
44785
  // We have to do it when the command handled is "PASTE", not "INSERT_CELL"
43806
44786
  // or "DELETE_CELL". So, the state should be the local state
43807
- const shouldPasteCF = clipboardOptions?.pasteOption !== "onlyValue" && clipboardOptions?.shouldPasteCF;
44787
+ const shouldPasteCF = clipboardOptions?.pasteOption !== "asValue" && clipboardOptions?.shouldPasteCF;
43808
44788
  const shouldPasteDV = !clipboardOptions?.pasteOption;
43809
44789
  const sheetId = this.getters.getActiveSheetId();
43810
44790
  // first, add missing cols/rows if needed
@@ -43840,10 +44820,11 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
43840
44820
  pasteCell(origin, target, operation, clipboardOption) {
43841
44821
  const { sheetId, col, row } = target;
43842
44822
  const targetCell = this.getters.getEvaluatedCell(target);
43843
- if (clipboardOption?.pasteOption === "onlyValue") {
44823
+ const originFormat = origin.cell?.format ?? origin.evaluatedCell.format;
44824
+ if (clipboardOption?.pasteOption === "asValue") {
43844
44825
  const locale = this.getters.getLocale();
43845
44826
  const content = formatValue(origin.evaluatedCell.value, { locale });
43846
- this.dispatch("UPDATE_CELL", { ...target, content });
44827
+ this.dispatch("UPDATE_CELL", { ...target, content, format: originFormat });
43847
44828
  return;
43848
44829
  }
43849
44830
  const targetBorders = this.getters.getCellBorder(target);
@@ -43859,7 +44840,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
43859
44840
  this.dispatch("UPDATE_CELL", {
43860
44841
  ...target,
43861
44842
  style: origin.cell?.style ?? null,
43862
- format: origin.cell?.format ?? origin.evaluatedCell.format ?? targetCell.format,
44843
+ format: originFormat ?? targetCell.format,
43863
44844
  });
43864
44845
  return;
43865
44846
  }
@@ -50062,6 +51043,20 @@ css /* scss */ `
50062
51043
  `;
50063
51044
  class RippleEffect extends Component {
50064
51045
  static template = "o-spreadsheet-RippleEffect";
51046
+ static props = {
51047
+ x: String,
51048
+ y: String,
51049
+ color: String,
51050
+ opacity: Number,
51051
+ duration: Number,
51052
+ width: Number,
51053
+ height: Number,
51054
+ offsetY: Number,
51055
+ offsetX: Number,
51056
+ allowOverflow: Boolean,
51057
+ onAnimationEnd: Function,
51058
+ style: String,
51059
+ };
50065
51060
  rippleRef = useRef("ripple");
50066
51061
  setup() {
50067
51062
  let animation = undefined;
@@ -50097,22 +51092,23 @@ class RippleEffect extends Component {
50097
51092
  });
50098
51093
  }
50099
51094
  }
50100
- RippleEffect.props = {
50101
- x: String,
50102
- y: String,
50103
- color: String,
50104
- opacity: Number,
50105
- duration: Number,
50106
- width: Number,
50107
- height: Number,
50108
- offsetY: Number,
50109
- offsetX: Number,
50110
- allowOverflow: Boolean,
50111
- onAnimationEnd: Function,
50112
- style: String,
50113
- };
50114
51095
  class Ripple extends Component {
50115
51096
  static template = "o-spreadsheet-Ripple";
51097
+ static props = {
51098
+ color: { type: String, optional: true },
51099
+ opacity: { type: Number, optional: true },
51100
+ duration: { type: Number, optional: true },
51101
+ ignoreClickPosition: { type: Boolean, optional: true },
51102
+ width: { type: Number, optional: true },
51103
+ height: { type: Number, optional: true },
51104
+ offsetY: { type: Number, optional: true },
51105
+ offsetX: { type: Number, optional: true },
51106
+ allowOverflow: { type: Boolean, optional: true },
51107
+ enabled: { type: Boolean, optional: true },
51108
+ onAnimationEnd: { type: Function, optional: true },
51109
+ slots: Object,
51110
+ class: { type: String, optional: true },
51111
+ };
50116
51112
  static components = { RippleEffect };
50117
51113
  static defaultProps = {
50118
51114
  color: "#aaaaaa",
@@ -50198,21 +51194,6 @@ class Ripple extends Component {
50198
51194
  };
50199
51195
  }
50200
51196
  }
50201
- Ripple.props = {
50202
- color: { type: String, optional: true },
50203
- opacity: { type: Number, optional: true },
50204
- duration: { type: Number, optional: true },
50205
- ignoreClickPosition: { type: Boolean, optional: true },
50206
- width: { type: Number, optional: true },
50207
- height: { type: Number, optional: true },
50208
- offsetY: { type: Number, optional: true },
50209
- offsetX: { type: Number, optional: true },
50210
- allowOverflow: { type: Boolean, optional: true },
50211
- enabled: { type: Boolean, optional: true },
50212
- onAnimationEnd: { type: Function, optional: true },
50213
- slots: Object,
50214
- class: { type: String, optional: true },
50215
- };
50216
51197
 
50217
51198
  function interactiveRenameSheet(env, sheetId, name, errorCallback) {
50218
51199
  const result = env.model.dispatch("RENAME_SHEET", { sheetId, name });
@@ -50270,6 +51251,12 @@ css /* scss */ `
50270
51251
  `;
50271
51252
  class BottomBarSheet extends Component {
50272
51253
  static template = "o-spreadsheet-BottomBarSheet";
51254
+ static props = {
51255
+ sheetId: String,
51256
+ openContextMenu: Function,
51257
+ style: { type: String, optional: true },
51258
+ onMouseDown: { type: Function, optional: true },
51259
+ };
50273
51260
  static components = { Ripple };
50274
51261
  static defaultProps = {
50275
51262
  onMouseDown: () => { },
@@ -50391,12 +51378,6 @@ class BottomBarSheet extends Component {
50391
51378
  return this.env.model.getters.getSheetName(this.props.sheetId);
50392
51379
  }
50393
51380
  }
50394
- BottomBarSheet.props = {
50395
- sheetId: String,
50396
- openContextMenu: Function,
50397
- style: { type: String, optional: true },
50398
- onMouseDown: { type: Function, optional: true },
50399
- };
50400
51381
 
50401
51382
  // -----------------------------------------------------------------------------
50402
51383
  // SpreadSheet
@@ -50414,6 +51395,10 @@ css /* scss */ `
50414
51395
  `;
50415
51396
  class BottomBarStatistic extends Component {
50416
51397
  static template = "o-spreadsheet-BottomBarStatisic";
51398
+ static props = {
51399
+ openContextMenu: Function,
51400
+ closeContextMenu: Function,
51401
+ };
50417
51402
  static components = { Ripple };
50418
51403
  selectedStatisticFn = "";
50419
51404
  statisticFnResults = {};
@@ -50460,10 +51445,6 @@ class BottomBarStatistic extends Component {
50460
51445
  return fnName + ": " + (fnValue !== undefined ? formatValue(fnValue, { locale }) : "__");
50461
51446
  }
50462
51447
  }
50463
- BottomBarStatistic.props = {
50464
- openContextMenu: Function,
50465
- closeContextMenu: Function,
50466
- };
50467
51448
 
50468
51449
  // -----------------------------------------------------------------------------
50469
51450
  // SpreadSheet
@@ -50514,6 +51495,9 @@ css /* scss */ `
50514
51495
  `;
50515
51496
  class BottomBar extends Component {
50516
51497
  static template = "o-spreadsheet-BottomBar";
51498
+ static props = {
51499
+ onClick: Function,
51500
+ };
50517
51501
  static components = { Menu, Ripple, BottomBarSheet, BottomBarStatistic };
50518
51502
  bottomBarRef = useRef("bottomBar");
50519
51503
  sheetListRef = useRef("sheetList");
@@ -50699,9 +51683,6 @@ class BottomBar extends Component {
50699
51683
  return this.sheetListRef.el.scrollWidth - this.sheetListRef.el.clientWidth;
50700
51684
  }
50701
51685
  }
50702
- BottomBar.props = {
50703
- onClick: Function,
50704
- };
50705
51686
 
50706
51687
  css /* scss */ `
50707
51688
  .o-dashboard-clickable-cell {
@@ -50712,6 +51693,7 @@ css /* scss */ `
50712
51693
  let tKey = 1;
50713
51694
  class SpreadsheetDashboard extends Component {
50714
51695
  static template = "o-spreadsheet-SpreadsheetDashboard";
51696
+ static props = {};
50715
51697
  static components = {
50716
51698
  GridOverlay,
50717
51699
  GridPopover,
@@ -50830,7 +51812,6 @@ class SpreadsheetDashboard extends Component {
50830
51812
  return { ...this.canvasPosition, ...this.env.model.getters.getSheetViewDimensionWithHeaders() };
50831
51813
  }
50832
51814
  }
50833
- SpreadsheetDashboard.props = {};
50834
51815
 
50835
51816
  css /* scss */ `
50836
51817
  .o-header-group {
@@ -50858,6 +51839,11 @@ css /* scss */ `
50858
51839
  `;
50859
51840
  class AbstractHeaderGroup extends Component {
50860
51841
  static template = "o-spreadsheet-HeaderGroup";
51842
+ static props = {
51843
+ group: Object,
51844
+ layerOffset: Number,
51845
+ openContextMenu: Function,
51846
+ };
50861
51847
  toggleGroup() {
50862
51848
  const sheetId = this.env.model.getters.getActiveSheetId();
50863
51849
  const { start, end } = this.props.group;
@@ -50894,11 +51880,6 @@ class AbstractHeaderGroup extends Component {
50894
51880
  this.props.openContextMenu(position, menuItems);
50895
51881
  }
50896
51882
  }
50897
- AbstractHeaderGroup.props = {
50898
- group: Object,
50899
- layerOffset: Number,
50900
- openContextMenu: Function,
50901
- };
50902
51883
  class RowGroup extends AbstractHeaderGroup {
50903
51884
  dimension = "ROW";
50904
51885
  get groupBorderStyle() {
@@ -51029,6 +52010,10 @@ css /* scss */ `
51029
52010
  `;
51030
52011
  class HeaderGroupContainer extends Component {
51031
52012
  static template = "o-spreadsheet-HeaderGroupContainer";
52013
+ static props = {
52014
+ dimension: String,
52015
+ layers: Array,
52016
+ };
51032
52017
  static components = { RowGroup, ColGroup, Menu };
51033
52018
  menu = useState({ isOpen: false, position: null, menuItems: [] });
51034
52019
  getLayerOffset(layerIndex) {
@@ -51091,10 +52076,6 @@ class HeaderGroupContainer extends Component {
51091
52076
  }
51092
52077
  }
51093
52078
  }
51094
- HeaderGroupContainer.props = {
51095
- dimension: String,
51096
- layers: Array,
51097
- };
51098
52079
 
51099
52080
  css /* scss */ `
51100
52081
  .o-sidePanel {
@@ -51205,14 +52186,6 @@ css /* scss */ `
51205
52186
  text-align: left;
51206
52187
  }
51207
52188
 
51208
- .o-checkbox {
51209
- display: flex;
51210
- justify-items: center;
51211
- input {
51212
- margin-right: 5px;
51213
- }
51214
- }
51215
-
51216
52189
  .o-inflection {
51217
52190
  table {
51218
52191
  table-layout: fixed;
@@ -51253,6 +52226,11 @@ css /* scss */ `
51253
52226
  `;
51254
52227
  class SidePanel extends Component {
51255
52228
  static template = "o-spreadsheet-SidePanel";
52229
+ static props = {
52230
+ component: String,
52231
+ panelProps: { type: Object, optional: true },
52232
+ onCloseSidePanel: Function,
52233
+ };
51256
52234
  state;
51257
52235
  setup() {
51258
52236
  this.state = useState({
@@ -51266,11 +52244,6 @@ class SidePanel extends Component {
51266
52244
  : this.state.panel.title;
51267
52245
  }
51268
52246
  }
51269
- SidePanel.props = {
51270
- component: String,
51271
- panelProps: { type: Object, optional: true },
51272
- onCloseSidePanel: Function,
51273
- };
51274
52247
 
51275
52248
  css /* scss */ `
51276
52249
  .o-menu-item-button {
@@ -51288,6 +52261,13 @@ css /* scss */ `
51288
52261
  `;
51289
52262
  class ActionButton extends Component {
51290
52263
  static template = "o-spreadsheet-ActionButton";
52264
+ static props = {
52265
+ action: Object,
52266
+ hasTriangleDownIcon: { type: Boolean, optional: true },
52267
+ selectedColor: { type: String, optional: true },
52268
+ class: { type: String, optional: true },
52269
+ onClick: { type: Function, optional: true },
52270
+ };
51291
52271
  actionButton = createAction(this.props.action);
51292
52272
  setup() {
51293
52273
  onWillUpdateProps((nextProps) => {
@@ -51330,13 +52310,6 @@ class ActionButton extends Component {
51330
52310
  return "";
51331
52311
  }
51332
52312
  }
51333
- ActionButton.props = {
51334
- action: Object,
51335
- hasTriangleDownIcon: { type: Boolean, optional: true },
51336
- selectedColor: { type: String, optional: true },
51337
- class: { type: String, optional: true },
51338
- onClick: { type: Function, optional: true },
51339
- };
51340
52313
 
51341
52314
  /**
51342
52315
  * List the available borders positions and the corresponding icons.
@@ -51433,6 +52406,17 @@ css /* scss */ `
51433
52406
  `;
51434
52407
  class BorderEditor extends Component {
51435
52408
  static template = "o-spreadsheet-BorderEditor";
52409
+ static props = {
52410
+ class: { type: String, optional: true },
52411
+ currentBorderColor: { type: String, optional: false },
52412
+ currentBorderStyle: { type: String, optional: false },
52413
+ currentBorderPosition: { type: String, optional: true },
52414
+ onBorderColorPicked: Function,
52415
+ onBorderStylePicked: Function,
52416
+ onBorderPositionPicked: Function,
52417
+ maxHeight: { type: Number, optional: true },
52418
+ anchorRect: Object,
52419
+ };
51436
52420
  static components = { ColorPickerWidget, Popover };
51437
52421
  BORDER_POSITIONS = BORDER_POSITIONS;
51438
52422
  lineStyleButtonRef = useRef("lineStyleButton");
@@ -51488,20 +52472,16 @@ class BorderEditor extends Component {
51488
52472
  };
51489
52473
  }
51490
52474
  }
51491
- BorderEditor.props = {
51492
- class: { type: String, optional: true },
51493
- currentBorderColor: { type: String, optional: false },
51494
- currentBorderStyle: { type: String, optional: false },
51495
- currentBorderPosition: { type: String, optional: true },
51496
- onBorderColorPicked: Function,
51497
- onBorderStylePicked: Function,
51498
- onBorderPositionPicked: Function,
51499
- maxHeight: { type: Number, optional: true },
51500
- anchorRect: Object,
51501
- };
51502
52475
 
51503
52476
  class BorderEditorWidget extends Component {
51504
52477
  static template = "o-spreadsheet-BorderEditorWidget";
52478
+ static props = {
52479
+ toggleBorderEditor: Function,
52480
+ showBorderEditor: Boolean,
52481
+ disabled: { type: Boolean, optional: true },
52482
+ dropdownMaxHeight: { type: Number, optional: true },
52483
+ class: { type: String, optional: true },
52484
+ };
51505
52485
  static components = { BorderEditor };
51506
52486
  borderEditorButtonRef = useRef("borderEditorButton");
51507
52487
  state = useState({
@@ -51546,13 +52526,6 @@ class BorderEditorWidget extends Component {
51546
52526
  });
51547
52527
  }
51548
52528
  }
51549
- BorderEditorWidget.props = {
51550
- toggleBorderEditor: Function,
51551
- showBorderEditor: Boolean,
51552
- disabled: { type: Boolean, optional: true },
51553
- dropdownMaxHeight: { type: Number, optional: true },
51554
- class: { type: String, optional: true },
51555
- };
51556
52529
 
51557
52530
  const COMPOSER_MAX_HEIGHT = 100;
51558
52531
  /* svg free of use from https://uxwing.com/formula-fx-icon/ */
@@ -51581,6 +52554,12 @@ css /* scss */ `
51581
52554
  `;
51582
52555
  class TopBarComposer extends Component {
51583
52556
  static template = "o-spreadsheet-TopBarComposer";
52557
+ static props = {
52558
+ focus: {
52559
+ validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
52560
+ },
52561
+ onComposerContentFocused: Function,
52562
+ };
51584
52563
  static components = { Composer };
51585
52564
  get composerStyle() {
51586
52565
  const style = {
@@ -51603,10 +52582,6 @@ class TopBarComposer extends Component {
51603
52582
  });
51604
52583
  }
51605
52584
  }
51606
- TopBarComposer.props = {
51607
- focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
51608
- onComposerContentFocused: Function,
51609
- };
51610
52585
 
51611
52586
  css /* scss */ `
51612
52587
  .o-font-size-editor {
@@ -51635,6 +52610,11 @@ css /* scss */ `
51635
52610
  `;
51636
52611
  class FontSizeEditor extends Component {
51637
52612
  static template = "o-spreadsheet-FontSizeEditor";
52613
+ static props = {
52614
+ onToggle: Function,
52615
+ dropdownStyle: String,
52616
+ class: String,
52617
+ };
51638
52618
  static components = {};
51639
52619
  fontSizes = FONT_SIZES;
51640
52620
  dropdown = useState({ isOpen: false });
@@ -51691,14 +52671,12 @@ class FontSizeEditor extends Component {
51691
52671
  }
51692
52672
  }
51693
52673
  }
51694
- FontSizeEditor.props = {
51695
- onToggle: Function,
51696
- dropdownStyle: String,
51697
- class: String,
51698
- };
51699
52674
 
51700
52675
  class PaintFormatButton extends Component {
51701
52676
  static template = "o-spreadsheet-PaintFormatButton";
52677
+ static props = {
52678
+ class: { type: String, optional: true },
52679
+ };
51702
52680
  get isActive() {
51703
52681
  return this.env.model.getters.isPaintingFormat();
51704
52682
  }
@@ -51714,9 +52692,6 @@ class PaintFormatButton extends Component {
51714
52692
  }
51715
52693
  }
51716
52694
  }
51717
- PaintFormatButton.props = {
51718
- class: { type: String, optional: true },
51719
- };
51720
52695
 
51721
52696
  // -----------------------------------------------------------------------------
51722
52697
  // TopBar
@@ -51809,6 +52784,12 @@ css /* scss */ `
51809
52784
  `;
51810
52785
  class TopBar extends Component {
51811
52786
  static template = "o-spreadsheet-TopBar";
52787
+ static props = {
52788
+ onClick: Function,
52789
+ focusComposer: String,
52790
+ onComposerContentFocused: Function,
52791
+ dropdownMaxHeight: Number,
52792
+ };
51812
52793
  get dropdownStyle() {
51813
52794
  return `max-height:${this.props.dropdownMaxHeight}px`;
51814
52795
  }
@@ -51925,12 +52906,6 @@ class TopBar extends Component {
51925
52906
  this.onClick();
51926
52907
  }
51927
52908
  }
51928
- TopBar.props = {
51929
- onClick: Function,
51930
- focusComposer: String,
51931
- onComposerContentFocused: Function,
51932
- dropdownMaxHeight: Number,
51933
- };
51934
52909
 
51935
52910
  function instantiateClipboard() {
51936
52911
  return new WebClipboardWrapper(navigator.clipboard);
@@ -52163,6 +53138,9 @@ css /* scss */ `
52163
53138
  `;
52164
53139
  class Spreadsheet extends Component {
52165
53140
  static template = "o-spreadsheet-Spreadsheet";
53141
+ static props = {
53142
+ model: Object,
53143
+ };
52166
53144
  static components = {
52167
53145
  TopBar,
52168
53146
  Grid,
@@ -52307,7 +53285,7 @@ class Spreadsheet extends Component {
52307
53285
  }
52308
53286
  onKeydown(ev) {
52309
53287
  let keyDownString = "";
52310
- if (ev.ctrlKey || ev.metaKey) {
53288
+ if (isCtrlKey(ev)) {
52311
53289
  keyDownString += "CTRL+";
52312
53290
  }
52313
53291
  keyDownString += ev.key.toUpperCase();
@@ -52375,9 +53353,6 @@ class Spreadsheet extends Component {
52375
53353
  return this.env.model.getters.getVisibleGroupLayers(sheetId, "COL");
52376
53354
  }
52377
53355
  }
52378
- Spreadsheet.props = {
52379
- model: Object,
52380
- };
52381
53356
 
52382
53357
  class LocalTransportService {
52383
53358
  listeners = [];
@@ -55044,7 +56019,8 @@ function addRows(construct, data, sheet) {
55044
56019
  }
55045
56020
  else if (cell.content && cell.content !== "") {
55046
56021
  const isTableHeader = isCellTableHeader(c, r, sheet);
55047
- ({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader));
56022
+ const isPlainText = !!(cell.format && data.formats[cell.format] === PLAIN_TEXT_FORMAT);
56023
+ ({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isPlainText));
55048
56024
  }
55049
56025
  attributes.push(...additionalAttrs);
55050
56026
  cellNodes.push(escapeXml /*xml*/ `
@@ -55973,6 +56949,7 @@ const helpers = {
55973
56949
  colorToRGBA,
55974
56950
  positionToZone,
55975
56951
  isDefined: isDefined$1,
56952
+ isMatrix,
55976
56953
  lazy,
55977
56954
  genericRepeat,
55978
56955
  createAction,
@@ -56022,6 +56999,6 @@ const constants = {
56022
56999
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
56023
57000
 
56024
57001
 
56025
- __info__.version = "17.1.0-alpha.5";
56026
- __info__.date = "2023-12-05T09:51:40.034Z";
56027
- __info__.hash = "c2823eb";
57002
+ __info__.version = "17.1.0-alpha.7";
57003
+ __info__.date = "2024-01-12T13:45:00.505Z";
57004
+ __info__.hash = "cbce1ed";