@odoo/o-spreadsheet 19.1.0-alpha.10 → 19.1.0-alpha.11

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 19.1.0-alpha.10
6
- * @date 2025-10-30T12:26:30.196Z
7
- * @hash d0b65e9
5
+ * @version 19.1.0-alpha.11
6
+ * @date 2025-11-03T12:34:28.925Z
7
+ * @hash d9230f3
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, useExternalListener, onWillUpdateProps, onWillStart, onWillPatch, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -156,6 +156,8 @@ const MOBILE_WIDTH_BREAKPOINT = 768;
156
156
  const MENU_WIDTH = 250;
157
157
  const MENU_VERTICAL_PADDING = 6;
158
158
  const DESKTOP_MENU_ITEM_HEIGHT = 26;
159
+ // Zoom
160
+ const ZOOM_VALUES = [50, 75, 100, 125, 150, 200];
159
161
  // Style
160
162
  const DEFAULT_STYLE = {
161
163
  align: "left",
@@ -2285,13 +2287,13 @@ function addMetaInfoFromArg(name, addDescr) {
2285
2287
  let optionalArg = 0;
2286
2288
  for (const arg of addDescr.args) {
2287
2289
  countArg++;
2288
- if (!arg.optional && !arg.repeating && !arg.default) {
2290
+ if (!arg.optional && !arg.default) {
2289
2291
  minArg++;
2290
2292
  }
2291
2293
  if (arg.repeating) {
2292
2294
  repeatingArg++;
2293
2295
  }
2294
- if (arg.optional || arg.default) {
2296
+ if ((arg.optional || arg.default) && !arg.repeating) {
2295
2297
  optionalArg++;
2296
2298
  }
2297
2299
  }
@@ -2299,7 +2301,7 @@ function addMetaInfoFromArg(name, addDescr) {
2299
2301
  descr.minArgRequired = minArg;
2300
2302
  descr.maxArgPossible = repeatingArg ? Infinity : countArg;
2301
2303
  descr.nbrArgRepeating = repeatingArg;
2302
- descr.nbrArgOptional = optionalArg;
2304
+ descr.nbrOptionalNonRepeatingArgs = optionalArg;
2303
2305
  descr.hidden = addDescr.hidden || false;
2304
2306
  descr.name = name;
2305
2307
  return descr;
@@ -2327,9 +2329,9 @@ const cacheArgTargeting = {};
2327
2329
  * and rows representing the correspondence with the argument index.
2328
2330
  *
2329
2331
  * The tables are built based on the following conventions:
2330
- * - `m`: Mandatory argument
2331
- * - `o`: Optional argument
2332
- * - `r`: Repeating argument
2332
+ * - `m`: Mandatory argument (count as one argument)
2333
+ * - `o`: Optional argument (count as zero or one argument)
2334
+ * - `r`: Repeating argument (count as one or more arguments)
2333
2335
  *
2334
2336
  *
2335
2337
  * Configuration 1: (m, o) like the CEILING function
@@ -2342,39 +2344,39 @@ const cacheArgTargeting = {};
2342
2344
  *
2343
2345
  * Configuration 2: (m, m, m, r, r) like the SUMIFS function
2344
2346
  *
2345
- * | | 3 | 5 | 7 | 3 + 2n |
2346
- * |---|---|---|------|------------|
2347
- * | m | 0 | 0 | 0 | 0 |
2348
- * | m | 1 | 1 | 1 | 1 |
2349
- * | m | 2 | 2 | 2 | 2 |
2350
- * | r | | 3 | 3, 5 | 3 + 2n |
2351
- * | r | | 4 | 4, 6 | 3 + 2n + 1 |
2347
+ * | | 5 | 7 | 3 + 2n |
2348
+ * |---|---|------|------------|
2349
+ * | m | 0 | 0 | 0 |
2350
+ * | m | 1 | 1 | 1 |
2351
+ * | m | 2 | 2 | 2 |
2352
+ * | r | 3 | 3, 5 | 3 + 2n |
2353
+ * | r | 4 | 4, 6 | 3 + 2n + 1 |
2352
2354
  *
2353
2355
  *
2354
2356
  * Configuration 3: (m, m, m, r, r, o) like the SWITCH function
2355
2357
  *
2356
- * | | 3 | 4 | 5 | 6 | 7 | 8 | 3 + 2n | 3 + 2n + 1 |
2357
- * |---|---|---|---|---|------|------|------------|----------------|
2358
- * | m | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2359
- * | m | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2360
- * | m | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
2361
- * | r | | | 3 | 3 | 3, 5 | 3, 5 | 3 + 2n | 3 + 2n |
2362
- * | r | | | 4 | 4 | 4, 6 | 4, 6 | 3 + 2n + 1 | 3 + 2n + 1 |
2363
- * | o | | 3 | | 5 | | 7 | | 3 + 2N + 2 |
2358
+ * | | 5 | 6 | 7 | 8 | 3 + 2n | 3 + 2n + 1 |
2359
+ * |---|---|---|------|------|------------|----------------|
2360
+ * | m | 0 | 0 | 0 | 0 | 0 | 0 |
2361
+ * | m | 1 | 1 | 1 | 1 | 1 | 1 |
2362
+ * | m | 2 | 2 | 2 | 2 | 2 | 2 |
2363
+ * | r | 3 | 3 | 3, 5 | 3, 5 | 3 + 2n | 3 + 2n |
2364
+ * | r | 4 | 4 | 4, 6 | 4, 6 | 3 + 2n + 1 | 3 + 2n + 1 |
2365
+ * | o | | 5 | | 7 | | 3 + 2N + 2 |
2364
2366
  *
2365
2367
  *
2366
2368
  * Configuration 4: (m, o, m, o, r, r, r, m) a complex case to understand subtleties
2367
2369
  *
2368
- * | | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ... |
2369
- * |---|---|---|---|---|---|---|------|------|------|-----|
2370
- * | m | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... |
2371
- * | o | | 1 | 1 | | 1 | 1 | | 1 | 1 | ... |
2372
- * | m | 1 | 2 | 2 | 1 | 2 | 2 | 1 | 2 | 2 | ... |
2373
- * | o | | | 3 | | | 3 | | | 3 | ... |
2374
- * | r | | | | 2 | 3 | 4 | 2, 5 | 3, 6 | 4, 7 | ... |
2375
- * | r | | | | 3 | 4 | 5 | 3, 6 | 4, 7 | 5, 8 | ... |
2376
- * | r | | | | 4 | 5 | 6 | 4, 7 | 5, 8 | 6, 9 | ... |
2377
- * | m | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... |
2370
+ * | | 6 | 7 | 8 | 9 | 10 | 11 | ... |
2371
+ * |---|---|---|---|------|------|------|-----|
2372
+ * | m | 0 | 0 | 0 | 0 | 0 | 0 | ... |
2373
+ * | o | | 1 | 1 | | 1 | 1 | ... |
2374
+ * | m | 1 | 2 | 2 | 1 | 2 | 2 | ... |
2375
+ * | o | | | 3 | | | 3 | ... |
2376
+ * | r | 2 | 3 | 4 | 2, 5 | 3, 6 | 4, 7 | ... |
2377
+ * | r | 3 | 4 | 5 | 3, 6 | 4, 7 | 5, 8 | ... |
2378
+ * | r | 4 | 5 | 6 | 4, 7 | 5, 8 | 6, 9 | ... |
2379
+ * | m | 5 | 6 | 7 | 8 | 9 | 10 | ... |
2378
2380
  *
2379
2381
  */
2380
2382
  function argTargeting(functionDescription, nbrArgSupplied) {
@@ -2393,30 +2395,31 @@ function argTargeting(functionDescription, nbrArgSupplied) {
2393
2395
  }
2394
2396
  function _argTargeting(functionDescription, nbrArgSupplied) {
2395
2397
  const valueIndexToArgPosition = {};
2396
- const groupsOfRepeatingValues = functionDescription.nbrArgRepeating
2398
+ const groupsOfOptionalRepeatingValues = functionDescription.nbrArgRepeating
2397
2399
  ? Math.floor((nbrArgSupplied - functionDescription.minArgRequired) / functionDescription.nbrArgRepeating)
2398
2400
  : 0;
2399
- const nbrValueRepeating = functionDescription.nbrArgRepeating * groupsOfRepeatingValues;
2400
- const nbrValueOptional = nbrArgSupplied - functionDescription.minArgRequired - nbrValueRepeating;
2401
+ const nbrValueOptionalRepeating = functionDescription.nbrArgRepeating * groupsOfOptionalRepeatingValues;
2402
+ const nbrValueOptional = nbrArgSupplied - functionDescription.minArgRequired - nbrValueOptionalRepeating;
2401
2403
  let countValueSupplied = 0;
2402
2404
  let countValueOptional = 0;
2403
2405
  for (let i = 0; i < functionDescription.args.length; i++) {
2404
2406
  const arg = functionDescription.args[i];
2405
- if (arg.optional || arg.default) {
2407
+ if ((arg.optional || arg.default) && !arg.repeating) {
2406
2408
  if (countValueOptional < nbrValueOptional) {
2407
- valueIndexToArgPosition[countValueSupplied] = i;
2409
+ valueIndexToArgPosition[countValueSupplied] = { index: i };
2408
2410
  countValueSupplied++;
2409
2411
  }
2410
2412
  countValueOptional++;
2411
2413
  continue;
2412
2414
  }
2413
2415
  if (arg.repeating) {
2416
+ const groupOfMandatoryRepeatingValues = arg.optional ? 0 : 1;
2414
2417
  // As we know all repeating arguments are consecutive,
2415
2418
  // --> we will treat all repeating arguments in one go
2416
2419
  // --> the index i will be incremented by the number of repeating values at the end of the loop
2417
- for (let j = 0; j < groupsOfRepeatingValues; j++) {
2420
+ for (let j = 0; j < groupsOfOptionalRepeatingValues + groupOfMandatoryRepeatingValues; j++) {
2418
2421
  for (let k = 0; k < functionDescription.nbrArgRepeating; k++) {
2419
- valueIndexToArgPosition[countValueSupplied] = i + k;
2422
+ valueIndexToArgPosition[countValueSupplied] = { index: i + k, repeatingGroupIndex: j };
2420
2423
  countValueSupplied++;
2421
2424
  }
2422
2425
  }
@@ -2424,7 +2427,7 @@ function _argTargeting(functionDescription, nbrArgSupplied) {
2424
2427
  continue;
2425
2428
  }
2426
2429
  // End case: it's a required argument
2427
- valueIndexToArgPosition[countValueSupplied] = i;
2430
+ valueIndexToArgPosition[countValueSupplied] = { index: i };
2428
2431
  countValueSupplied++;
2429
2432
  }
2430
2433
  return (argPosition) => {
@@ -2436,7 +2439,7 @@ function _argTargeting(functionDescription, nbrArgSupplied) {
2436
2439
  //------------------------------------------------------------------------------
2437
2440
  const META_TYPES = ["META", "RANGE<META>"];
2438
2441
  function validateArguments(descr) {
2439
- if (descr.nbrArgRepeating && descr.nbrArgOptional >= descr.nbrArgRepeating) {
2442
+ if (descr.nbrArgRepeating && descr.nbrOptionalNonRepeatingArgs >= descr.nbrArgRepeating) {
2440
2443
  throw new Error(`Function ${descr.name} has more optional arguments than repeatable ones.`);
2441
2444
  }
2442
2445
  let foundRepeating = false;
@@ -4122,7 +4125,7 @@ function createComputeFunction(descr) {
4122
4125
  const getArgToFocus = argTargeting(descr, args.length);
4123
4126
  //#region Compute vectorisation limits
4124
4127
  for (let i = 0; i < args.length; i++) {
4125
- const argIndex = getArgToFocus(i) ?? -1;
4128
+ const argIndex = getArgToFocus(i).index ?? -1;
4126
4129
  const argDefinition = descr.args[argIndex];
4127
4130
  const arg = args[i];
4128
4131
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
@@ -4136,7 +4139,7 @@ function createComputeFunction(descr) {
4136
4139
  for (let i = 0; i < args.length; i++) {
4137
4140
  const arg = args[i];
4138
4141
  const getArgToFocus = argTargeting(descr, args.length);
4139
- const argDefinition = descr.args[getArgToFocus(i) || i];
4142
+ const argDefinition = descr.args[getArgToFocus(i).index ?? i];
4140
4143
  // Early exit if the argument is an error and the function does not accept errors
4141
4144
  // We only check scalar arguments, not matrix arguments for performance reasons.
4142
4145
  // Casting helpers are responsible for handling errors in matrix arguments.
@@ -4404,8 +4407,7 @@ const CHOOSECOLS = {
4404
4407
  description: _t$1("Creates a new array from the selected columns in the existing range."),
4405
4408
  args: [
4406
4409
  arg("array (any, range<any>)", _t$1("The array that contains the columns to be returned.")),
4407
- arg("col_num (number, range<number>)", _t$1("The first column index of the columns to be returned.")),
4408
- arg("col_num2 (number, range<number>, repeating)", _t$1("The columns indexes of the columns to be returned.")),
4410
+ arg("col_num (number, range<number>, repeating)", _t$1("The column index of the column to be returned.")),
4409
4411
  ],
4410
4412
  compute: function (array, ...columns) {
4411
4413
  const _array = toMatrix(array);
@@ -4434,8 +4436,7 @@ const CHOOSEROWS = {
4434
4436
  description: _t$1("Creates a new array from the selected rows in the existing range."),
4435
4437
  args: [
4436
4438
  arg("array (any, range<any>)", _t$1("The array that contains the rows to be returned.")),
4437
- arg("row_num (number, range<number>)", _t$1("The first row index of the rows to be returned.")),
4438
- arg("row_num2 (number, range<number>, repeating)", _t$1("The rows indexes of the rows to be returned.")),
4439
+ arg("row_num (number, range<number>, repeating)", _t$1("The row index of the row to be returned.")),
4439
4440
  ],
4440
4441
  compute: function (array, ...rows) {
4441
4442
  const _array = toMatrix(array);
@@ -4485,10 +4486,7 @@ const EXPAND = {
4485
4486
  // -----------------------------------------------------------------------------
4486
4487
  const FLATTEN = {
4487
4488
  description: _t$1("Flattens all the values from one or more ranges into a single column."),
4488
- args: [
4489
- arg("range (any, range<any>)", _t$1("The first range to flatten.")),
4490
- arg("range2 (any, range<any>, repeating)", _t$1("Additional ranges to flatten.")),
4491
- ],
4489
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to flatten."))],
4492
4490
  compute: function (...ranges) {
4493
4491
  return [flattenRowFirst(ranges, (val) => (val === undefined ? { value: "" } : val))];
4494
4492
  },
@@ -4546,10 +4544,7 @@ const FREQUENCY = {
4546
4544
  // -----------------------------------------------------------------------------
4547
4545
  const HSTACK = {
4548
4546
  description: _t$1("Appends ranges horizontally and in sequence to return a larger array."),
4549
- args: [
4550
- arg("range1 (any, range<any>)", _t$1("The first range to be appended.")),
4551
- arg("range2 (any, range<any>, repeating)", _t$1("Additional ranges to add to range1.")),
4552
- ],
4547
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to be appended."))],
4553
4548
  compute: function (...ranges) {
4554
4549
  const nbRows = Math.max(...ranges.map((r) => r?.[0]?.length ?? 0));
4555
4550
  const result = [];
@@ -4635,8 +4630,7 @@ const MMULT = {
4635
4630
  const SUMPRODUCT = {
4636
4631
  description: _t$1("Calculates the sum of the products of corresponding entries in equal-sized ranges."),
4637
4632
  args: [
4638
- arg("range1 (number, range<number>)", _t$1("The first range whose entries will be multiplied with corresponding entries in the other ranges.")),
4639
- arg("range2 (number, range<number>, repeating)", _t$1("The other range whose entries will be multiplied with corresponding entries in the other ranges.")),
4633
+ arg("range (number, range<number>, repeating)", _t$1("The range whose entries will be multiplied with corresponding entries in the other range.")),
4640
4634
  ],
4641
4635
  compute: function (...args) {
4642
4636
  if (!areSameDimensions(...args)) {
@@ -4822,10 +4816,7 @@ const TRANSPOSE = {
4822
4816
  // -----------------------------------------------------------------------------
4823
4817
  const VSTACK = {
4824
4818
  description: _t$1("Appends ranges vertically and in sequence to return a larger array."),
4825
- args: [
4826
- arg("range1 (any, range<any>)", _t$1("The first range to be appended.")),
4827
- arg("range2 (any, range<any>, repeating)", _t$1("Additional ranges to add to range1.")),
4828
- ],
4819
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to be appended."))],
4829
4820
  compute: function (...ranges) {
4830
4821
  const nbColumns = Math.max(...ranges.map((range) => toMatrix(range).length));
4831
4822
  const nbRows = ranges.reduce((acc, range) => acc + toMatrix(range)[0].length, 0);
@@ -6392,6 +6383,7 @@ const readonlyAllowedCommands = new Set([
6392
6383
  "COPY",
6393
6384
  "RESIZE_SHEETVIEW",
6394
6385
  "SET_VIEWPORT_OFFSET",
6386
+ "SET_ZOOM",
6395
6387
  "EVALUATE_CELLS",
6396
6388
  "EVALUATE_CHARTS",
6397
6389
  "SET_FORMULA_VISIBILITY",
@@ -7107,8 +7099,7 @@ const COTH = {
7107
7099
  const COUNTBLANK = {
7108
7100
  description: _t$1("Number of empty values."),
7109
7101
  args: [
7110
- arg("value1 (any, range)", _t$1("The first value or range in which to count the number of blanks.")),
7111
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges in which to count the number of blanks.")),
7102
+ arg("value (any, range, repeating)", _t$1("Value or range in which to count the number of blanks.")),
7112
7103
  ],
7113
7104
  compute: function (...args) {
7114
7105
  return reduceAny(args, (acc, a) => {
@@ -7150,10 +7141,8 @@ const COUNTIF = {
7150
7141
  const COUNTIFS = {
7151
7142
  description: _t$1("Count values depending on multiple criteria."),
7152
7143
  args: [
7153
- arg("criteria_range1 (range)", _t$1("The range to check against criterion1.")),
7154
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1.")),
7155
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
7156
- arg("criterion2 (string, repeating)", _t$1("Additional criteria to check.")),
7144
+ arg("criteria_range (any, range, repeating)", _t$1("Range over which to evaluate criteria.")),
7145
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7157
7146
  ],
7158
7147
  compute: function (...args) {
7159
7148
  let count = 0;
@@ -7169,10 +7158,7 @@ const COUNTIFS = {
7169
7158
  // -----------------------------------------------------------------------------
7170
7159
  const COUNTUNIQUE = {
7171
7160
  description: _t$1("Counts number of unique values in a range."),
7172
- args: [
7173
- arg("value1 (any, range)", _t$1("The first value or range to consider for uniqueness.")),
7174
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges to consider for uniqueness.")),
7175
- ],
7161
+ args: [arg("value (any, range, repeating)", _t$1("Value or range to consider for uniqueness."))],
7176
7162
  compute: function (...args) {
7177
7163
  return countUnique(args);
7178
7164
  },
@@ -7184,10 +7170,8 @@ const COUNTUNIQUEIFS = {
7184
7170
  description: _t$1("Counts number of unique values in a range, filtered by a set of criteria."),
7185
7171
  args: [
7186
7172
  arg("range (range)", _t$1("The range of cells from which the number of unique values will be counted.")),
7187
- arg("criteria_range1 (range)", _t$1("The range of cells over which to evaluate criterion1.")),
7188
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1, such that each cell that evaluates to TRUE will be included in the filtered set.")),
7189
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
7190
- arg("criterion2 (string, repeating)", _t$1("The pattern or test to apply to criteria_range2.")),
7173
+ arg("criteria_range (any, range, repeating)", _t$1("Range over which to evaluate criteria.")),
7174
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7191
7175
  ],
7192
7176
  compute: function (range, ...args) {
7193
7177
  const uniqueValues = new Set();
@@ -7543,8 +7527,7 @@ const POWER = {
7543
7527
  const PRODUCT = {
7544
7528
  description: _t$1("Result of multiplying a series of numbers together."),
7545
7529
  args: [
7546
- arg("factor1 (number, range<number>)", _t$1("The first number or range to calculate for the product.")),
7547
- arg("factor2 (number, range<number>, repeating)", _t$1("More numbers or ranges to calculate for the product.")),
7530
+ arg("factor (number, range<number>, repeating)", _t$1("Number or range to calculate for the product.")),
7548
7531
  ],
7549
7532
  compute: function (...factors) {
7550
7533
  let count = 0;
@@ -7876,8 +7859,7 @@ const SUBTOTAL = {
7876
7859
  ...subtotalFunctionOptionsIncludeHiddenRows,
7877
7860
  ...subtotalFunctionOptionsExcludeHiddenRows,
7878
7861
  ]),
7879
- arg("ref1 (meta, range<meta>)", _t$1("The range or reference for which you want the subtotal.")),
7880
- arg("ref2 (meta, range<meta>, repeating)", _t$1("Additional ranges or references for which you want the subtotal.")),
7862
+ arg("ref (meta, range<meta>, repeating)", _t$1("Range or reference for which you want the subtotal.")),
7881
7863
  ],
7882
7864
  compute: function (functionCode, ...refs) {
7883
7865
  let code = toInteger(functionCode, this.locale);
@@ -7921,10 +7903,7 @@ const SUBTOTAL = {
7921
7903
  // -----------------------------------------------------------------------------
7922
7904
  const SUM = {
7923
7905
  description: _t$1("Sum of a series of numbers and/or cells."),
7924
- args: [
7925
- arg("value1 (number, range<number>)", _t$1("The first number or range to add together.")),
7926
- arg("value2 (number, range<number>, repeating)", _t$1("Additional numbers or ranges to add to value1.")),
7927
- ],
7906
+ args: [arg("value (number, range<number>, repeating)", _t$1("Number or range to add together."))],
7928
7907
  compute: function (...values) {
7929
7908
  const v1 = values[0];
7930
7909
  return {
@@ -7966,10 +7945,8 @@ const SUMIFS = {
7966
7945
  description: _t$1("Sums a range depending on multiple criteria."),
7967
7946
  args: [
7968
7947
  arg("sum_range (range)", _t$1("The range to sum.")),
7969
- arg("criteria_range1 (range)", _t$1("The range to check against criterion1.")),
7970
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1.")),
7971
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges to check.")),
7972
- arg("criterion2 (string, repeating)", _t$1("Additional criteria to check.")),
7948
+ arg("criteria_range (any, range, repeating)", _t$1("Range to check.")),
7949
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7973
7950
  ],
7974
7951
  compute: function (sumRange, ...criters) {
7975
7952
  let sum = 0;
@@ -8451,8 +8428,7 @@ function centile(data, percent, isInclusive, locale) {
8451
8428
  const AVEDEV = {
8452
8429
  description: _t$1("Average magnitude of deviations from mean."),
8453
8430
  args: [
8454
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
8455
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
8431
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
8456
8432
  ],
8457
8433
  compute: function (...values) {
8458
8434
  let count = 0;
@@ -8474,8 +8450,7 @@ const AVEDEV = {
8474
8450
  const AVERAGE = {
8475
8451
  description: _t$1("Numerical average value in a dataset, ignoring text."),
8476
8452
  args: [
8477
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the average value.")),
8478
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the average value.")),
8453
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the average value.")),
8479
8454
  ],
8480
8455
  compute: function (...values) {
8481
8456
  return {
@@ -8493,10 +8468,8 @@ const negativeWeightError = _t$1("[[FUNCTION_NAME]] expects the weight to be pos
8493
8468
  const AVERAGE_WEIGHTED = {
8494
8469
  description: _t$1("Weighted average."),
8495
8470
  args: [
8496
- arg("values (number, range<number>)", _t$1("Values to average.")),
8497
- arg("weights (number, range<number>)", _t$1("Weights for each corresponding value.")),
8498
- arg("additional_values (number, range<number>, repeating)", _t$1("Additional values to average.")),
8499
- arg("additional_weights (number, range<number>, repeating)", _t$1("Additional weights.")),
8471
+ arg("values (number, range<number>, repeating)", _t$1("Value to average.")),
8472
+ arg("weights (number, range<number>, repeating)", _t$1("Weight for each corresponding value.")),
8500
8473
  ],
8501
8474
  compute: function (...args) {
8502
8475
  let sum = 0;
@@ -8552,8 +8525,7 @@ const AVERAGE_WEIGHTED = {
8552
8525
  const AVERAGEA = {
8553
8526
  description: _t$1("Numerical average value in a dataset."),
8554
8527
  args: [
8555
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the average value.")),
8556
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the average value.")),
8528
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the average value.")),
8557
8529
  ],
8558
8530
  compute: function (...args) {
8559
8531
  let count = 0;
@@ -8606,10 +8578,8 @@ const AVERAGEIFS = {
8606
8578
  description: _t$1("Average of values depending on multiple criteria."),
8607
8579
  args: [
8608
8580
  arg("average_range (range)", _t$1("The range to average.")),
8609
- arg("criteria_range1 (range)", _t$1("The range to check against criterion1.")),
8610
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1.")),
8611
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional criteria_range and criterion to check.")),
8612
- arg("criterion2 (string, repeating)", _t$1("The pattern or test to apply to criteria_range2.")),
8581
+ arg("criteria_range (any, range, repeating)", _t$1("Range to check.")),
8582
+ arg("criterion (string, repeating)", _t$1("Criterion to check.")),
8613
8583
  ],
8614
8584
  compute: function (averageRange, ...args) {
8615
8585
  const _averageRange = toMatrix(averageRange);
@@ -8635,8 +8605,7 @@ const AVERAGEIFS = {
8635
8605
  const COUNT = {
8636
8606
  description: _t$1("The number of numeric values in dataset."),
8637
8607
  args: [
8638
- arg("value1 (number, any, range<number>)", _t$1("The first value or range to consider when counting.")),
8639
- arg("value2 (number, any, range<number>, repeating)", _t$1("Additional values or ranges to consider when counting.")),
8608
+ arg("value (number, any, range<number>, repeating)", _t$1("Value or range to consider when counting.")),
8640
8609
  ],
8641
8610
  compute: function (...values) {
8642
8611
  return countNumbers(values, this.locale);
@@ -8648,10 +8617,7 @@ const COUNT = {
8648
8617
  // -----------------------------------------------------------------------------
8649
8618
  const COUNTA = {
8650
8619
  description: _t$1("The number of values in a dataset."),
8651
- args: [
8652
- arg("value1 (any, range)", _t$1("The first value or range to consider when counting.")),
8653
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges to consider when counting.")),
8654
- ],
8620
+ args: [arg("value (any, range, repeating)", _t$1("Value or range to consider when counting."))],
8655
8621
  compute: function (...values) {
8656
8622
  return countAny(values);
8657
8623
  },
@@ -8884,8 +8850,7 @@ const MATTHEWS = {
8884
8850
  const MAX = {
8885
8851
  description: _t$1("Maximum value in a numeric dataset."),
8886
8852
  args: [
8887
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the maximum value.")),
8888
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the maximum value.")),
8853
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the maximum value.")),
8889
8854
  ],
8890
8855
  compute: function (...values) {
8891
8856
  return max(values, this.locale);
@@ -8898,8 +8863,7 @@ const MAX = {
8898
8863
  const MAXA = {
8899
8864
  description: _t$1("Maximum numeric value in a dataset."),
8900
8865
  args: [
8901
- arg("value1 (any, range)", _t$1("The first value or range to consider when calculating the maximum value.")),
8902
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges to consider when calculating the maximum value.")),
8866
+ arg("value (any, range, repeating)", _t$1("Value or range to consider when calculating the maximum value.")),
8903
8867
  ],
8904
8868
  compute: function (...args) {
8905
8869
  const maxa = reduceNumbersTextAs0(args, (acc, a) => {
@@ -8916,10 +8880,8 @@ const MAXIFS = {
8916
8880
  description: _t$1("Returns the maximum value in a range of cells, filtered by a set of criteria."),
8917
8881
  args: [
8918
8882
  arg("range (range)", _t$1("The range of cells from which the maximum will be determined.")),
8919
- arg("criteria_range1 (range)", _t$1("The range of cells over which to evaluate criterion1.")),
8920
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1, such that each cell that evaluates to TRUE will be included in the filtered set.")),
8921
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
8922
- arg("criterion2 (string, repeating)", _t$1("The pattern or test to apply to criteria_range2.")),
8883
+ arg("criteria_range (any, range, repeating)", _t$1("Range to evaluate criteria.")),
8884
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
8923
8885
  ],
8924
8886
  compute: function (range, ...args) {
8925
8887
  let result = -Infinity;
@@ -8939,8 +8901,7 @@ const MAXIFS = {
8939
8901
  const MEDIAN = {
8940
8902
  description: _t$1("Median value in a numeric dataset."),
8941
8903
  args: [
8942
- arg("value1 (any, range)", _t$1("The first value or range to consider when calculating the median value.")),
8943
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges to consider when calculating the median value.")),
8904
+ arg("value (any, range, repeating)", _t$1("Value or range to consider when calculating the median value.")),
8944
8905
  ],
8945
8906
  compute: function (...values) {
8946
8907
  const data = [];
@@ -8960,8 +8921,7 @@ const MEDIAN = {
8960
8921
  const MIN = {
8961
8922
  description: _t$1("Minimum value in a numeric dataset."),
8962
8923
  args: [
8963
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the minimum value.")),
8964
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the minimum value.")),
8924
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the minimum value.")),
8965
8925
  ],
8966
8926
  compute: function (...values) {
8967
8927
  return min(values, this.locale);
@@ -8974,8 +8934,7 @@ const MIN = {
8974
8934
  const MINA = {
8975
8935
  description: _t$1("Minimum numeric value in a dataset."),
8976
8936
  args: [
8977
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the minimum value.")),
8978
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the minimum value.")),
8937
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the minimum value.")),
8979
8938
  ],
8980
8939
  compute: function (...args) {
8981
8940
  const mina = reduceNumbersTextAs0(args, (acc, a) => {
@@ -8992,10 +8951,8 @@ const MINIFS = {
8992
8951
  description: _t$1("Returns the minimum value in a range of cells, filtered by a set of criteria."),
8993
8952
  args: [
8994
8953
  arg("range (range)", _t$1("The range of cells from which the minimum will be determined.")),
8995
- arg("criteria_range1 (range)", _t$1("The range of cells over which to evaluate criterion1.")),
8996
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1, such that each cell that evaluates to TRUE will be included in the filtered set.")),
8997
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
8998
- arg("criterion2 (string, repeating)", _t$1("The pattern or test to apply to criteria_range2.")),
8954
+ arg("criteria_range (any, range, repeating)", _t$1("Range to evaluate criteria.")),
8955
+ arg("criterion (string, repeating)", _t$1("Criterion to check.")),
8999
8956
  ],
9000
8957
  compute: function (range, ...args) {
9001
8958
  let result = Infinity;
@@ -9336,8 +9293,7 @@ const SPEARMAN = {
9336
9293
  const STDEV = {
9337
9294
  description: _t$1("Standard deviation."),
9338
9295
  args: [
9339
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9340
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9296
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9341
9297
  ],
9342
9298
  compute: function (...args) {
9343
9299
  return Math.sqrt(VAR.compute.bind(this)(...args));
@@ -9350,8 +9306,7 @@ const STDEV = {
9350
9306
  const STDEV_P = {
9351
9307
  description: _t$1("Standard deviation of entire population."),
9352
9308
  args: [
9353
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9354
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9309
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9355
9310
  ],
9356
9311
  compute: function (...args) {
9357
9312
  return Math.sqrt(VAR_P.compute.bind(this)(...args));
@@ -9364,8 +9319,7 @@ const STDEV_P = {
9364
9319
  const STDEV_S = {
9365
9320
  description: _t$1("Standard deviation."),
9366
9321
  args: [
9367
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9368
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9322
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9369
9323
  ],
9370
9324
  compute: function (...args) {
9371
9325
  return Math.sqrt(VAR_S.compute.bind(this)(...args));
@@ -9378,8 +9332,7 @@ const STDEV_S = {
9378
9332
  const STDEVA = {
9379
9333
  description: _t$1("Standard deviation of sample (text as 0)."),
9380
9334
  args: [
9381
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9382
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9335
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9383
9336
  ],
9384
9337
  compute: function (...args) {
9385
9338
  return Math.sqrt(VARA.compute.bind(this)(...args));
@@ -9392,8 +9345,7 @@ const STDEVA = {
9392
9345
  const STDEVP = {
9393
9346
  description: _t$1("Standard deviation of entire population."),
9394
9347
  args: [
9395
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9396
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9348
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9397
9349
  ],
9398
9350
  compute: function (...args) {
9399
9351
  return Math.sqrt(VARP.compute.bind(this)(...args));
@@ -9406,8 +9358,7 @@ const STDEVP = {
9406
9358
  const STDEVPA = {
9407
9359
  description: _t$1("Standard deviation of entire population (text as 0)."),
9408
9360
  args: [
9409
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9410
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9361
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9411
9362
  ],
9412
9363
  compute: function (...args) {
9413
9364
  return Math.sqrt(VARPA.compute.bind(this)(...args));
@@ -9457,8 +9408,7 @@ const TREND = {
9457
9408
  const VAR = {
9458
9409
  description: _t$1("Variance."),
9459
9410
  args: [
9460
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9461
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9411
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9462
9412
  ],
9463
9413
  compute: function (...args) {
9464
9414
  return variance(args, true, false, this.locale);
@@ -9471,8 +9421,7 @@ const VAR = {
9471
9421
  const VAR_P = {
9472
9422
  description: _t$1("Variance of entire population."),
9473
9423
  args: [
9474
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9475
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9424
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9476
9425
  ],
9477
9426
  compute: function (...args) {
9478
9427
  return variance(args, false, false, this.locale);
@@ -9485,8 +9434,7 @@ const VAR_P = {
9485
9434
  const VAR_S = {
9486
9435
  description: _t$1("Variance."),
9487
9436
  args: [
9488
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9489
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9437
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9490
9438
  ],
9491
9439
  compute: function (...args) {
9492
9440
  return variance(args, true, false, this.locale);
@@ -9499,8 +9447,7 @@ const VAR_S = {
9499
9447
  const VARA = {
9500
9448
  description: _t$1("Variance of sample (text as 0)."),
9501
9449
  args: [
9502
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9503
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9450
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9504
9451
  ],
9505
9452
  compute: function (...args) {
9506
9453
  return variance(args, true, true, this.locale);
@@ -9513,8 +9460,7 @@ const VARA = {
9513
9460
  const VARP = {
9514
9461
  description: _t$1("Variance of entire population."),
9515
9462
  args: [
9516
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9517
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9463
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9518
9464
  ],
9519
9465
  compute: function (...args) {
9520
9466
  return variance(args, false, false, this.locale);
@@ -9527,8 +9473,7 @@ const VARP = {
9527
9473
  const VARPA = {
9528
9474
  description: _t$1("Variance of entire population (text as 0)."),
9529
9475
  args: [
9530
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9531
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9476
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9532
9477
  ],
9533
9478
  compute: function (...args) {
9534
9479
  return variance(args, false, true, this.locale);
@@ -11432,8 +11377,7 @@ const FILTER = {
11432
11377
  // TODO modify args description when vectorization on formulas is available
11433
11378
  args: [
11434
11379
  arg("range (any, range<any>)", _t$1("The data to be filtered.")),
11435
- arg("condition1 (boolean, range<boolean>)", _t$1("A column or row containing true or false values corresponding to the first column or row of range.")),
11436
- arg("condition2 (boolean, range<boolean>, repeating)", _t$1("Additional column or row containing true or false values.")),
11380
+ arg("condition (boolean, range<boolean>, repeating)", _t$1("Column or row containing true or false values corresponding to the range.")),
11437
11381
  ],
11438
11382
  compute: function (range, ...conditions) {
11439
11383
  let _array = toMatrix(range);
@@ -11473,8 +11417,8 @@ const SORT = {
11473
11417
  description: _t$1("Sorts the rows of a given array or range by the values in one or more columns."),
11474
11418
  args: [
11475
11419
  arg("range (range)", _t$1("The data to be sorted.")),
11476
- arg("sort_column (any, range<number>, repeating)", _t$1("The index of the column in range or a range outside of range containing the values by which to sort.")),
11477
- arg("is_ascending (boolean, repeating)", _t$1("TRUE or FALSE indicating whether to sort sort_column in ascending order."), [
11420
+ arg("sort_column (any, range<number>, repeating, optional)", _t$1("The index of the column in range or a range outside of range containing the value by which to sort.")),
11421
+ arg("is_ascending (boolean, repeating, optional)", _t$1("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order."), [
11478
11422
  { value: true, label: _t$1("Ascending") },
11479
11423
  { value: false, label: _t$1("Descending") },
11480
11424
  ]),
@@ -11494,8 +11438,8 @@ const SORTN = {
11494
11438
  arg("range (range)", _t$1("The data to be sorted.")),
11495
11439
  arg("n (number)", _t$1("The number of items to return.")),
11496
11440
  arg("display_ties_mode (number, default=0)", _t$1("A number representing the way to display ties.")),
11497
- arg("sort_column (number, range<number>, repeating)", _t$1("The index of the column in range or a range outside of range containing the values by which to sort.")),
11498
- arg("is_ascending (boolean, repeating)", _t$1("TRUE or FALSE indicating whether to sort sort_column in ascending order."), [
11441
+ arg("sort_column (number, range<number>, repeating, optional)", _t$1("The index of the column in range or a range outside of range containing the value by which to sort.")),
11442
+ arg("is_ascending (boolean, repeating, optional)", _t$1("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order."), [
11499
11443
  { value: true, label: _t$1("Ascending") },
11500
11444
  { value: false, label: _t$1("Descending") },
11501
11445
  ]),
@@ -12763,8 +12707,7 @@ const NPV = {
12763
12707
  description: _t$1("The net present value of an investment based on a series of periodic cash flows and a discount rate."),
12764
12708
  args: [
12765
12709
  arg("discount (number)", _t$1("The discount rate of the investment over one period.")),
12766
- arg("cashflow1 (number, range<number>)", _t$1("The first future cash flow.")),
12767
- arg("cashflow2 (number, range<number>, repeating)", _t$1("Additional future cash flows.")),
12710
+ arg("cashflow (number, range<number>, repeating)", _t$1("The future cash flows.")),
12768
12711
  ],
12769
12712
  // to do: replace by dollar format
12770
12713
  compute: function (discount, ...values) {
@@ -14119,8 +14062,7 @@ function boolOr(args) {
14119
14062
  const AND = {
14120
14063
  description: _t$1("Logical `and` operator."),
14121
14064
  args: [
14122
- arg("logical_expression1 (boolean, range<boolean>)", _t$1("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
14123
- arg("logical_expression2 (boolean, range<boolean>, repeating)", _t$1("More expressions that represent logical values.")),
14065
+ arg("logical_expression (boolean, range<boolean>, repeating)", _t$1("Expression or reference to a cell containing a logical value (TRUE/FALSE) or an expression that can be coerced to a logical value.")),
14124
14066
  ],
14125
14067
  compute: function (...logicalExpressions) {
14126
14068
  const { result, foundBoolean } = boolAnd(logicalExpressions);
@@ -14203,10 +14145,8 @@ const IFNA = {
14203
14145
  const IFS = {
14204
14146
  description: _t$1("Returns a value depending on multiple logical expressions."),
14205
14147
  args: [
14206
- arg("condition1 (boolean, range<boolean>)", _t$1("The first condition to be evaluated. This can be a boolean, a number, an array, or a reference to any of those.")),
14207
- arg("value1 (any, range)", _t$1("The returned value if condition1 is TRUE.")),
14208
- arg("condition2 (boolean, any, range, repeating)", _t$1("Additional conditions to be evaluated if the previous ones are FALSE.")),
14209
- arg("value2 (any, range, repeating)", _t$1("Additional values to be returned if their corresponding conditions are TRUE.")),
14148
+ arg("condition (any, range, repeating)", _t$1("The condition to be evaluated. It can be a boolean, a number, an array, or a reference to any of those.")),
14149
+ arg("value (any, range, repeating)", _t$1("The value to be returned if its corresponding condition is TRUE.")),
14210
14150
  ],
14211
14151
  compute: function (...values) {
14212
14152
  if (values.length % 2 !== 0) {
@@ -14245,8 +14185,7 @@ const NOT = {
14245
14185
  const OR = {
14246
14186
  description: _t$1("Logical `or` operator."),
14247
14187
  args: [
14248
- arg("logical_expression1 (boolean, range<boolean>)", _t$1("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
14249
- arg("logical_expression2 (boolean, range<boolean>, repeating)", _t$1("More expressions that evaluate to logical values.")),
14188
+ arg("logical_expression (boolean, range<boolean>, repeating)", _t$1("Expression or reference to a cell containing a logical value (TRUE/FALSE) or an expression that can be coerced to a logical value.")),
14250
14189
  ],
14251
14190
  compute: function (...logicalExpressions) {
14252
14191
  const { result, foundBoolean } = boolOr(logicalExpressions);
@@ -14264,10 +14203,8 @@ const SWITCH = {
14264
14203
  description: _t$1("Returns a value by comparing cases to an expression."),
14265
14204
  args: [
14266
14205
  arg("expression (number, boolean, string)", _t$1("The value to be checked.")),
14267
- arg("case1 (number, boolean, string)", _t$1("The first case to be checked against expression.")),
14268
- arg("value1 (any)", _t$1("The corresponding value to be returned if case1 matches expression.")),
14269
- arg("case2 (any, repeating)", _t$1("Additional cases to try if the previous ones don't match expression.")),
14270
- arg("value2 (any, repeating)", _t$1("Additional values to be returned if their corresponding cases match expression.")),
14206
+ arg("case (any, repeating)", _t$1("Case to be checked against expression.")),
14207
+ arg("value (any, repeating)", _t$1("Value to be returned if its corresponding case matches expression.")),
14271
14208
  arg(`default (any, default="empty")`, _t$1("An optional default value to be returned if none of the cases match expression.")),
14272
14209
  ],
14273
14210
  compute: function (expression, ...casesAndValues) {
@@ -14302,8 +14239,7 @@ const TRUE = {
14302
14239
  const XOR = {
14303
14240
  description: _t$1("Logical `xor` operator."),
14304
14241
  args: [
14305
- arg("logical_expression1 (boolean, range<boolean>)", _t$1("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
14306
- arg("logical_expression2 (boolean, range<boolean>, repeating)", _t$1("More expressions that evaluate to logical values.")),
14242
+ arg("logical_expression (boolean, range<boolean>, repeating)", _t$1("Expression or reference to a cell containing a logical value (TRUE/FALSE) or an expression that can be coerced to a logical value.")),
14307
14243
  ],
14308
14244
  compute: function (...logicalExpressions) {
14309
14245
  let foundBoolean = false;
@@ -15816,8 +15752,8 @@ const PIVOT_VALUE = {
15816
15752
  args: [
15817
15753
  arg("pivot_id (number,string)", _t$1("ID of the pivot.")),
15818
15754
  arg("measure_name (string)", _t$1("Name of the measure.")),
15819
- arg("domain_field_name (string,repeating)", _t$1("Field name.")),
15820
- arg("domain_value (number,string,boolean,repeating)", _t$1("Value.")),
15755
+ arg("domain_field_name (string,repeating,optional)", _t$1("Field name.")),
15756
+ arg("domain_value (number,string,boolean,repeating,optional)", _t$1("Value.")),
15821
15757
  ],
15822
15758
  compute: function (formulaId, measureName, ...domainArgs) {
15823
15759
  const _pivotFormulaId = toString(formulaId);
@@ -15852,8 +15788,8 @@ const PIVOT_HEADER = {
15852
15788
  description: _t$1("Get the header of a pivot."),
15853
15789
  args: [
15854
15790
  arg("pivot_id (number,string)", _t$1("ID of the pivot.")),
15855
- arg("domain_field_name (string,repeating)", _t$1("Field name.")),
15856
- arg("domain_value (number,string,value,repeating)", _t$1("Value.")),
15791
+ arg("domain_field_name (string,repeating,optional)", _t$1("Field name.")),
15792
+ arg("domain_value (number,string,value,repeating,optional)", _t$1("Value.")),
15857
15793
  ],
15858
15794
  compute: function (pivotId, ...domainArgs) {
15859
15795
  const _pivotFormulaId = toString(pivotId);
@@ -16724,10 +16660,7 @@ const CLEAN = {
16724
16660
  // -----------------------------------------------------------------------------
16725
16661
  const CONCATENATE = {
16726
16662
  description: _t$1("Appends strings to one another."),
16727
- args: [
16728
- arg("string1 (string, range<string>)", _t$1("The initial string.")),
16729
- arg("string2 (string, range<string>, repeating)", _t$1("More strings to append in sequence.")),
16730
- ],
16663
+ args: [arg("string (string, range<string>, repeating)", _t$1("String to append in sequence."))],
16731
16664
  compute: function (...datas) {
16732
16665
  return reduceAny(datas, (acc, a) => acc + toString(a), "");
16733
16666
  },
@@ -16782,8 +16715,7 @@ const JOIN = {
16782
16715
  description: _t$1("Concatenates elements of arrays with delimiter."),
16783
16716
  args: [
16784
16717
  arg("delimiter (string)", _t$1("The character or string to place between each concatenated value.")),
16785
- arg("value_or_array1 (string, range<string>)", _t$1("The value or values to be appended using delimiter.")),
16786
- arg("value_or_array2 (string, range<string>, repeating)", _t$1("More values to be appended using delimiter.")),
16718
+ arg("value_or_array (string, range<string>, repeating)", _t$1("Value to be appended using delimiter.")),
16787
16719
  ],
16788
16720
  compute: function (delimiter, ...valuesOrArrays) {
16789
16721
  const _delimiter = toString(delimiter);
@@ -17074,13 +17006,12 @@ const TEXTJOIN_DEFAULT_IGNORE_EMPTY = true;
17074
17006
  const TEXTJOIN = {
17075
17007
  description: _t$1("Combines text from multiple strings and/or arrays."),
17076
17008
  args: [
17077
- arg("delimiter (string)", _t$1(" A string, possible empty, or a reference to a valid string. If empty, the text will be simply concatenated.")),
17009
+ arg("delimiter (string)", _t$1("A string, possible empty, or a reference to a valid string. If empty, the text will be simply concatenated.")),
17078
17010
  arg("ignore_empty (boolean)", _t$1("A boolean; if TRUE, empty cells selected in the text arguments won't be included in the result."), [
17079
17011
  { value: true, label: _t$1("Ignore empty cells") },
17080
17012
  { value: false, label: _t$1("Include empty cells (default)") },
17081
17013
  ]),
17082
- arg("text1 (string, range<string>)", _t$1("Any text item. This could be a string, or an array of strings in a range.")),
17083
- arg("text2 (string, range<string>, repeating)", _t$1("Additional text item(s).")),
17014
+ arg("texts (string, range<string>, repeating)", _t$1("Text item to join.")),
17084
17015
  ],
17085
17016
  compute: function (delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
17086
17017
  const _delimiter = toString(delimiter);
@@ -22968,6 +22899,66 @@ class ScorecardChartConfigBuilder {
22968
22899
  }
22969
22900
  }
22970
22901
 
22902
+ /**
22903
+ * Return a POJO containing the original event as well as the client position and the client offset
22904
+ * where the event would target if the spreadsheet was not zoomed
22905
+ * @param ev unzoomed mouse event
22906
+ * @param originalTargetRect The original target bounding rect the resulting ZoomedMouseEvent offset must refer to
22907
+ * @returns a ZoomedMouseEvent
22908
+ */
22909
+ function withZoom(env, ev, originalTargetRect) {
22910
+ const zoomLevel = env.model.getters.getViewportZoomLevel();
22911
+ if (originalTargetRect === undefined) {
22912
+ originalTargetRect = getZoomTargetBoundingRect(ev);
22913
+ }
22914
+ if (!originalTargetRect)
22915
+ return withNoZoom(ev);
22916
+ const baseOffsetX = ev.clientX - originalTargetRect.left;
22917
+ const baseOffsetY = ev.clientY - originalTargetRect.top;
22918
+ const offsetX = baseOffsetX / zoomLevel;
22919
+ const offsetY = baseOffsetY / zoomLevel;
22920
+ return {
22921
+ ev,
22922
+ clientX: ev.clientX - baseOffsetX + offsetX,
22923
+ clientY: ev.clientY - baseOffsetY + offsetY,
22924
+ offsetX,
22925
+ offsetY,
22926
+ };
22927
+ }
22928
+ function withNoZoom(ev) {
22929
+ return {
22930
+ ev,
22931
+ clientX: ev.clientX,
22932
+ clientY: ev.clientY,
22933
+ offsetX: ev.offsetX,
22934
+ offsetY: ev.offsetY,
22935
+ };
22936
+ }
22937
+ /**
22938
+ * Return a Rect with position and size on the zoomed canvas
22939
+ */
22940
+ function getZoomedRect(zoom, rect) {
22941
+ return {
22942
+ height: rect.height * zoom,
22943
+ width: rect.width * zoom,
22944
+ x: rect.x * zoom,
22945
+ y: rect.y * zoom,
22946
+ };
22947
+ }
22948
+ /**
22949
+ * Returns the bounding rect of the closest or self element who is targetable by a ZoomedMouseEvent
22950
+ */
22951
+ function getZoomTargetBoundingRect(ev) {
22952
+ const target = ev.target;
22953
+ if (!target || !("classList" in target) || !(target instanceof Element)) {
22954
+ return null;
22955
+ }
22956
+ const targetEl = target.classList.contains("o-zoomable") ? target : target.closest(".o-zoomable");
22957
+ if (!targetEl)
22958
+ return null;
22959
+ return targetEl.getBoundingClientRect();
22960
+ }
22961
+
22971
22962
  class ScorecardChart extends Component {
22972
22963
  static template = "o-spreadsheet-ScorecardChart";
22973
22964
  static props = {
@@ -22991,7 +22982,8 @@ class ScorecardChart extends Component {
22991
22982
  }
22992
22983
  createChart() {
22993
22984
  const canvas = this.canvas.el;
22994
- const config = getScorecardConfiguration(canvas.getBoundingClientRect(), this.runtime);
22985
+ const zoom = this.env.model.getters.getViewportZoomLevel();
22986
+ const config = getScorecardConfiguration(getZoomedRect(1 / zoom, canvas.getBoundingClientRect()), this.runtime);
22995
22987
  drawScoreChart(config, canvas);
22996
22988
  }
22997
22989
  }
@@ -23110,8 +23102,7 @@ function isChildEvent(parent, ev) {
23110
23102
  function gridOverlayPosition() {
23111
23103
  const spreadsheetElement = document.querySelector(".o-grid-overlay");
23112
23104
  if (spreadsheetElement) {
23113
- const { top, left } = spreadsheetElement.getBoundingClientRect();
23114
- return { top, left };
23105
+ return spreadsheetElement.getBoundingClientRect();
23115
23106
  }
23116
23107
  throw new Error("Can't find spreadsheet position");
23117
23108
  }
@@ -26253,7 +26244,7 @@ function compileTokensOrThrow(tokens) {
26253
26244
  const compiledArgs = [];
26254
26245
  const argToFocus = argTargeting(functionDefinition, args.length);
26255
26246
  for (let i = 0; i < args.length; i++) {
26256
- const argDefinition = functionDefinition.args[argToFocus(i) ?? -1];
26247
+ const argDefinition = functionDefinition.args[argToFocus(i).index ?? -1];
26257
26248
  const currentArg = args[i];
26258
26249
  const argTypes = argDefinition.type || [];
26259
26250
  // detect when an argument need to be evaluated as a meta argument
@@ -26432,12 +26423,15 @@ function assertEnoughArgs(ast) {
26432
26423
  }
26433
26424
  if (nbrArgRepeating > 1) {
26434
26425
  const nbrValueRepeating = nbrArgRepeating * Math.floor((nbrArgSupplied - minArgRequired) / nbrArgRepeating);
26435
- const nbrValueRemaining = nbrArgSupplied - minArgRequired - nbrValueRepeating - functionDefinition.nbrArgOptional;
26426
+ const nbrValueRemaining = nbrArgSupplied -
26427
+ minArgRequired -
26428
+ nbrValueRepeating -
26429
+ functionDefinition.nbrOptionalNonRepeatingArgs;
26436
26430
  if (nbrValueRemaining > 0) {
26437
26431
  throw new BadExpressionError(_t$1("Invalid number of arguments for the %(functionName)s function. Repeatable arguments should be supplied in groups of %(nbrArgRepeating)s, with up to %(nbrArgOptional)s optional. Got %(nbrValueRemaining)s too many.", {
26438
26432
  functionName,
26439
26433
  nbrArgRepeating,
26440
- nbrArgOptional: functionDefinition.nbrArgOptional,
26434
+ nbrArgOptional: functionDefinition.nbrOptionalNonRepeatingArgs,
26441
26435
  nbrValueRemaining,
26442
26436
  }));
26443
26437
  }
@@ -44834,8 +44828,24 @@ function astToDoc(ast) {
44834
44828
  case "REFERENCE":
44835
44829
  return ast.value;
44836
44830
  case "FUNCALL":
44837
- const docs = ast.args.map(astToDoc);
44838
- return wrapInParentheses(concat(docs.map((doc, i) => (i < 1 ? doc : concat([", ", line(), doc])))), ast.value);
44831
+ const functionDescription = functionRegistry.get(ast.value.toUpperCase());
44832
+ const getArgToFocus = argTargeting(functionDescription, ast.args.length);
44833
+ const docs = [];
44834
+ let i = 0;
44835
+ while (i < ast.args.length) {
44836
+ const isRepeating = functionDescription.args[getArgToFocus(i).index ?? -1]?.repeating;
44837
+ if (isRepeating) {
44838
+ const repeatingArgSeries = ast.args.slice(i, i + functionDescription.nbrArgRepeating);
44839
+ const docsSeries = repeatingArgSeries.map((arg) => astToDoc(arg));
44840
+ docs.push(group(concat(splitArgsWithCommas(docsSeries))));
44841
+ i += functionDescription.nbrArgRepeating;
44842
+ }
44843
+ else {
44844
+ docs.push(astToDoc(ast.args[i]));
44845
+ i++;
44846
+ }
44847
+ }
44848
+ return wrapInParentheses(concat(splitArgsWithCommas(docs)), ast.value);
44839
44849
  case "UNARY_OPERATION":
44840
44850
  const operandDoc = astToDoc(ast.operand);
44841
44851
  const needParenthesis = ast.postfix
@@ -44861,6 +44871,14 @@ function astToDoc(ast) {
44861
44871
  return "";
44862
44872
  }
44863
44873
  }
44874
+ function splitArgsWithCommas(docs) {
44875
+ const result = docs.length ? [docs[0]] : [];
44876
+ for (let i = 1; i < docs.length; i++) {
44877
+ result.push(", ", line());
44878
+ result.push(docs[i]);
44879
+ }
44880
+ return result;
44881
+ }
44864
44882
  /**
44865
44883
  * Wraps a `Doc` in parentheses (with optional function name).
44866
44884
  */
@@ -46468,6 +46486,7 @@ pivotRegistry.add("SPREADSHEET", {
46468
46486
  isMeasureCandidate: (field) => field.type !== "boolean",
46469
46487
  isGroupable: () => true,
46470
46488
  canHaveCustomGroup: (field) => field.type === "char" && !field.isCustomField,
46489
+ isPivotUnused: () => true,
46471
46490
  });
46472
46491
 
46473
46492
  const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT", "REMOVE_PIVOT"];
@@ -46486,7 +46505,7 @@ class PivotUIPlugin extends CoreViewPlugin {
46486
46505
  "isSpillPivotFormula",
46487
46506
  ];
46488
46507
  pivots = {};
46489
- unusedPivots;
46508
+ unusedPivotsInFormulas;
46490
46509
  custom;
46491
46510
  constructor(config) {
46492
46511
  super(config);
@@ -46526,12 +46545,12 @@ class PivotUIPlugin extends CoreViewPlugin {
46526
46545
  }
46527
46546
  case "DELETE_SHEET":
46528
46547
  case "UPDATE_CELL": {
46529
- this.unusedPivots = undefined;
46548
+ this.unusedPivotsInFormulas = undefined;
46530
46549
  break;
46531
46550
  }
46532
46551
  case "UNDO":
46533
46552
  case "REDO": {
46534
- this.unusedPivots = undefined;
46553
+ this.unusedPivotsInFormulas = undefined;
46535
46554
  const pivotCommands = cmd.commands.filter(isPivotCommand);
46536
46555
  for (const cmd of pivotCommands) {
46537
46556
  const pivotId = cmd.pivotId;
@@ -46690,7 +46709,9 @@ class PivotUIPlugin extends CoreViewPlugin {
46690
46709
  return this.pivots[pivotId];
46691
46710
  }
46692
46711
  isPivotUnused(pivotId) {
46693
- return this._getUnusedPivots().includes(pivotId);
46712
+ const { type } = this.getters.getPivot(pivotId);
46713
+ return (this._getUnusedPivotsInFormulas().includes(pivotId) &&
46714
+ pivotRegistry.get(type).isPivotUnused(this.getters, pivotId));
46694
46715
  }
46695
46716
  getPivotCellSortDirection(position) {
46696
46717
  const pivotId = this.getters.getPivotIdFromPosition(position);
@@ -46726,9 +46747,9 @@ class PivotUIPlugin extends CoreViewPlugin {
46726
46747
  this.pivots[pivotId].onDefinitionChange(definition);
46727
46748
  }
46728
46749
  }
46729
- _getUnusedPivots() {
46730
- if (this.unusedPivots !== undefined) {
46731
- return this.unusedPivots;
46750
+ _getUnusedPivotsInFormulas() {
46751
+ if (this.unusedPivotsInFormulas !== undefined) {
46752
+ return this.unusedPivotsInFormulas;
46732
46753
  }
46733
46754
  const unusedPivots = new Set(this.getters.getPivotIds());
46734
46755
  for (const sheetId of this.getters.getSheetIds()) {
@@ -46738,14 +46759,14 @@ class PivotUIPlugin extends CoreViewPlugin {
46738
46759
  if (pivotId) {
46739
46760
  unusedPivots.delete(pivotId);
46740
46761
  if (!unusedPivots.size) {
46741
- this.unusedPivots = [];
46762
+ this.unusedPivotsInFormulas = [];
46742
46763
  return [];
46743
46764
  }
46744
46765
  }
46745
46766
  }
46746
46767
  }
46747
- this.unusedPivots = [...unusedPivots];
46748
- return this.unusedPivots;
46768
+ this.unusedPivotsInFormulas = [...unusedPivots];
46769
+ return this.unusedPivotsInFormulas;
46749
46770
  }
46750
46771
  }
46751
46772
 
@@ -52150,6 +52171,7 @@ class SheetViewPlugin extends UIPlugin {
52150
52171
  "getVisibleFigures",
52151
52172
  "getVisibleRect",
52152
52173
  "getVisibleRectWithoutHeaders",
52174
+ "getVisibleRectWithZoom",
52153
52175
  "getVisibleCellPositions",
52154
52176
  "getColRowOffsetInViewport",
52155
52177
  "getMainViewportCoordinates",
@@ -52165,6 +52187,8 @@ class SheetViewPlugin extends UIPlugin {
52165
52187
  "getFigureUI",
52166
52188
  "getPositionAnchorOffset",
52167
52189
  "getGridOffset",
52190
+ "getViewportZoomLevel",
52191
+ "getScrollBarWidth",
52168
52192
  ];
52169
52193
  viewports = {};
52170
52194
  /**
@@ -52177,6 +52201,7 @@ class SheetViewPlugin extends UIPlugin {
52177
52201
  sheetViewHeight = getDefaultSheetViewSize();
52178
52202
  gridOffsetX = 0;
52179
52203
  gridOffsetY = 0;
52204
+ zoomLevel = 1;
52180
52205
  sheetsWithDirtyViewports = new Set();
52181
52206
  shouldAdjustViewports = false;
52182
52207
  // ---------------------------------------------------------------------------
@@ -52243,6 +52268,9 @@ class SheetViewPlugin extends UIPlugin {
52243
52268
  case "SET_VIEWPORT_OFFSET":
52244
52269
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
52245
52270
  break;
52271
+ case "SET_ZOOM":
52272
+ this.zoomLevel = cmd.zoom || 1;
52273
+ break;
52246
52274
  case "SHIFT_VIEWPORT_DOWN":
52247
52275
  const sheetId = this.getters.getActiveSheetId();
52248
52276
  const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
@@ -52446,7 +52474,7 @@ class SheetViewPlugin extends UIPlugin {
52446
52474
  for (const i of relevantIndexes) {
52447
52475
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
52448
52476
  }
52449
- return offset;
52477
+ return offset * this.zoomLevel;
52450
52478
  }
52451
52479
  /**
52452
52480
  * Check if a given position is visible in the viewport.
@@ -52454,6 +52482,9 @@ class SheetViewPlugin extends UIPlugin {
52454
52482
  isVisibleInViewport({ sheetId, col, row }) {
52455
52483
  return this.getSubViewports(sheetId).some((pane) => pane.isVisible(col, row));
52456
52484
  }
52485
+ getScrollBarWidth() {
52486
+ return SCROLLBAR_WIDTH / this.zoomLevel;
52487
+ }
52457
52488
  // => returns the new offset
52458
52489
  getEdgeScrollCol(x, previousX, startingX) {
52459
52490
  let canEdgeScroll = false;
@@ -52532,6 +52563,18 @@ class SheetViewPlugin extends UIPlugin {
52532
52563
  const rect = this.getVisibleRectWithoutHeaders(zone);
52533
52564
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
52534
52565
  }
52566
+ /**
52567
+ * Computes the coordinates and size to draw the zone on the canvas after it has been zoomed
52568
+ */
52569
+ getVisibleRectWithZoom(zone) {
52570
+ const zoom = this.getViewportZoomLevel();
52571
+ const rect = this.getVisibleRectWithoutHeaders(zone);
52572
+ rect.width = rect.width * zoom;
52573
+ rect.height = rect.height * zoom;
52574
+ rect.x = rect.x * zoom + this.gridOffsetX * zoom;
52575
+ rect.y = rect.y * zoom + this.gridOffsetY * zoom;
52576
+ return rect;
52577
+ }
52535
52578
  /**
52536
52579
  * Computes the coordinates and size to draw the zone without taking the grid offset into account
52537
52580
  */
@@ -52613,6 +52656,9 @@ class SheetViewPlugin extends UIPlugin {
52613
52656
  };
52614
52657
  });
52615
52658
  }
52659
+ getViewportZoomLevel() {
52660
+ return this.zoomLevel;
52661
+ }
52616
52662
  // ---------------------------------------------------------------------------
52617
52663
  // Private
52618
52664
  // ---------------------------------------------------------------------------
@@ -58260,22 +58306,26 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58260
58306
  }
58261
58307
  onPointerDownInMasterChart(ev) {
58262
58308
  this.removeEventListeners();
58263
- const position = ev.offsetX;
58309
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58310
+ const position = zoomedEvent.offsetX;
58264
58311
  if (!this.masterChart?.chartArea || !this.chart?.scales?.x) {
58265
58312
  return;
58266
58313
  }
58267
58314
  const { left, right, top, bottom } = this.masterChart.chartArea;
58268
58315
  const xMax = this.upperBound ?? right;
58269
58316
  const xMin = this.lowerBound ?? left;
58270
- if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
58317
+ if (position < left - 5 ||
58318
+ position > right + 5 ||
58319
+ zoomedEvent.offsetY < top ||
58320
+ zoomedEvent.offsetY > bottom) {
58271
58321
  return;
58272
58322
  }
58273
58323
  ev.preventDefault();
58274
58324
  ev.stopPropagation();
58275
58325
  let startingPositionOnChart, windowSize, startX;
58276
- const startingEventPosition = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58326
+ const startingEventPosition = position;
58277
58327
  if ((xMin !== left || xMax !== right) && position > xMin + 5 && position < xMax - 5) {
58278
- startingPositionOnChart = ev.offsetX - xMin;
58328
+ startingPositionOnChart = zoomedEvent.offsetX - xMin;
58279
58329
  this.mode = "moveInMaster";
58280
58330
  const currentLimits = this.store.currentAxesLimits[this.chartId]?.x;
58281
58331
  windowSize =
@@ -58324,7 +58374,8 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58324
58374
  return { min: xMin, max: xMax };
58325
58375
  };
58326
58376
  const onDragFromMasterChart = (ev) => {
58327
- const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58377
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58378
+ const position = zoomedEvent.offsetX;
58328
58379
  if (Math.abs(position - startingEventPosition) < 5) {
58329
58380
  return;
58330
58381
  }
@@ -58335,7 +58386,8 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58335
58386
  };
58336
58387
  const onPointerUpInMasterChart = (ev) => {
58337
58388
  this.removeEventListeners();
58338
- const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58389
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58390
+ const position = zoomedEvent.offsetX;
58339
58391
  if (Math.abs(position - startingEventPosition) > 5) {
58340
58392
  let { min: xMin, max: xMax } = computeNewAxisLimits(position);
58341
58393
  if (xMin !== undefined && xMax !== undefined) {
@@ -58362,7 +58414,7 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58362
58414
  window.addEventListener("pointerup", onPointerUpInMasterChart, true);
58363
58415
  }
58364
58416
  onPointerMoveInMasterChart(ev) {
58365
- const { offsetX: x, offsetY: y } = ev;
58417
+ const { offsetX: x, offsetY: y } = withZoom(this.env, ev, ev.target?.getBoundingClientRect());
58366
58418
  if (this.mode === undefined) {
58367
58419
  const target = ev.target;
58368
58420
  if (!this.masterChart?.chartArea) {
@@ -58395,7 +58447,8 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58395
58447
  }
58396
58448
  onDoubleClickInMasterChart(ev) {
58397
58449
  this.mode = undefined;
58398
- const position = ev.offsetX;
58450
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58451
+ const position = zoomedEvent.offsetX;
58399
58452
  if (!this.masterChart?.chartArea || !this.chart?.scales.x) {
58400
58453
  return;
58401
58454
  }
@@ -58405,7 +58458,10 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58405
58458
  if (upperBound < lowerBound) {
58406
58459
  [upperBound, lowerBound] = [lowerBound, upperBound];
58407
58460
  }
58408
- if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
58461
+ if (position < left - 5 ||
58462
+ position > right + 5 ||
58463
+ zoomedEvent.offsetY < top ||
58464
+ zoomedEvent.offsetY > bottom) {
58409
58465
  return;
58410
58466
  }
58411
58467
  ev.preventDefault();
@@ -58840,7 +58896,7 @@ class GaugeChartComponent extends Component {
58840
58896
  });
58841
58897
  }
58842
58898
  drawGaugeWithAnimation() {
58843
- drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue: 0 });
58899
+ drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue: 0 }, undefined);
58844
58900
  const gaugeValue = this.runtime.gaugeValue?.value || 0;
58845
58901
  const upperBound = this.runtime.maxValue.value;
58846
58902
  const finalValue = Math.sign(gaugeValue) * Math.min(Math.abs(gaugeValue), Math.abs(upperBound));
@@ -58848,7 +58904,7 @@ class GaugeChartComponent extends Component {
58848
58904
  return null;
58849
58905
  }
58850
58906
  const lowerBound = this.runtime.minValue.value;
58851
- const animation = new Animation(lowerBound, finalValue, ANIMATION_DURATION, (animationValue) => drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue }));
58907
+ const animation = new Animation(lowerBound, finalValue, ANIMATION_DURATION, (animationValue) => drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue }, undefined));
58852
58908
  animation.start();
58853
58909
  return animation;
58854
58910
  }
@@ -60068,7 +60124,13 @@ class FigureComponent extends Component {
60068
60124
  onContextMenu(ev) {
60069
60125
  if (this.env.isDashboard())
60070
60126
  return;
60071
- this.openContextMenu({ x: ev.clientX, y: ev.clientY, width: 0, height: 0 });
60127
+ const zoomedMouseEvent = withZoom(this.env, ev);
60128
+ this.openContextMenu({
60129
+ x: zoomedMouseEvent.clientX,
60130
+ y: zoomedMouseEvent.clientY,
60131
+ width: 0,
60132
+ height: 0,
60133
+ });
60072
60134
  }
60073
60135
  showMenu() {
60074
60136
  this.openContextMenu(getRefBoundingRect(this.menuButtonRef));
@@ -61904,7 +61966,7 @@ class ContentEditableHelper {
61904
61966
  else {
61905
61967
  text += NEWLINE;
61906
61968
  }
61907
- emptyParagraph = ["<br>", "<span><br></span>"].includes(current.value.innerHTML);
61969
+ emptyParagraph = isEmptyParagraph(current.value);
61908
61970
  continue;
61909
61971
  }
61910
61972
  if (!current.value.hasChildNodes()) {
@@ -61925,12 +61987,28 @@ function compareContentToSpanElement(content, node) {
61925
61987
  const sameContent = node.innerText === content.value;
61926
61988
  return sameColor && sameClass && sameContent;
61927
61989
  }
61990
+ const doc = new DOMParser();
61991
+ const brNode = doc.parseFromString("<br>", "text/html").body.firstChild;
61992
+ const spanBrNode = doc.parseFromString("<span><br></span>", "text/html").body.firstChild;
61993
+ function isEmptyParagraph(node) {
61994
+ if (node.childNodes.length > 1)
61995
+ return false;
61996
+ const node2 = node.firstChild?.cloneNode(true);
61997
+ if (!node2)
61998
+ return true;
61999
+ if (!(node2 instanceof Element))
62000
+ return false;
62001
+ node2.removeAttribute("class");
62002
+ node2.removeAttribute("style");
62003
+ return node2.isEqualNode(brNode) || node2.isEqualNode(spanBrNode) || false;
62004
+ }
61928
62005
 
61929
62006
  class FunctionDescriptionProvider extends Component {
61930
62007
  static template = "o-spreadsheet-FunctionDescriptionProvider";
61931
62008
  static props = {
61932
62009
  functionDescription: Object,
61933
62010
  argsToFocus: Array,
62011
+ repeatingArgGroupIndex: { type: Number, optional: true },
61934
62012
  };
61935
62013
  static components = { Collapse };
61936
62014
  state = useState({
@@ -61942,8 +62020,70 @@ class FunctionDescriptionProvider extends Component {
61942
62020
  getContext() {
61943
62021
  return this.props;
61944
62022
  }
61945
- get formulaArgSeparator() {
61946
- return this.env.model.getters.getLocale().formulaArgSeparator + " ";
62023
+ get formulaHeaderContent() {
62024
+ const { functionDescription, repeatingArgGroupIndex, argsToFocus } = this.props;
62025
+ const argSeparator = this.env.model.getters.getLocale().formulaArgSeparator + " ";
62026
+ const result = [
62027
+ { content: functionDescription.name + " ( " },
62028
+ ];
62029
+ for (let i = 0; i < functionDescription.args.length; i++) {
62030
+ const arg = functionDescription.args[i];
62031
+ const isRepeating = arg.repeating;
62032
+ if (i > 0) {
62033
+ result.push({ content: argSeparator });
62034
+ }
62035
+ if (isRepeating) {
62036
+ // treat all repeating args in one go
62037
+ const displayBrackets = arg.optional || (repeatingArgGroupIndex ?? 0) > 0;
62038
+ const repeatingArgNames = functionDescription.args
62039
+ .slice(i, i + functionDescription.nbrArgRepeating)
62040
+ .map((arg) => arg.name);
62041
+ if (repeatingArgGroupIndex) {
62042
+ result.push({ content: "... " + argSeparator });
62043
+ }
62044
+ if (displayBrackets) {
62045
+ result.push({ content: "[" });
62046
+ }
62047
+ for (let idx = 0; idx < repeatingArgNames.length; idx++) {
62048
+ const name = repeatingArgNames[idx];
62049
+ const argIndex = i + idx;
62050
+ const focused = argsToFocus.includes(argIndex);
62051
+ result.push({ content: name + ((repeatingArgGroupIndex ?? 0) + 1), focused });
62052
+ // Add separator after each element except the last
62053
+ if (idx < repeatingArgNames.length - 1) {
62054
+ result.push({ content: argSeparator });
62055
+ }
62056
+ }
62057
+ if (displayBrackets) {
62058
+ result.push({ content: "]" });
62059
+ }
62060
+ result.push({ content: argSeparator + "[" });
62061
+ for (let idx = 0; idx < repeatingArgNames.length; idx++) {
62062
+ const name = repeatingArgNames[idx];
62063
+ result.push({ content: name + ((repeatingArgGroupIndex ?? 0) + 2) });
62064
+ // Add separator after each element except the last
62065
+ if (idx < repeatingArgNames.length - 1) {
62066
+ result.push({ content: argSeparator });
62067
+ }
62068
+ }
62069
+ result.push({ content: "]" + argSeparator + "... " });
62070
+ // Skip the processed repeating args
62071
+ i += functionDescription.nbrArgRepeating - 1;
62072
+ }
62073
+ else {
62074
+ const displayBrackets = arg.optional || arg.default;
62075
+ const focused = argsToFocus.includes(i);
62076
+ if (displayBrackets) {
62077
+ result.push({ content: "[" });
62078
+ }
62079
+ result.push({ content: arg.name, focused });
62080
+ if (displayBrackets) {
62081
+ result.push({ content: "]" });
62082
+ }
62083
+ }
62084
+ }
62085
+ result.push({ content: " )" });
62086
+ return result;
61947
62087
  }
61948
62088
  }
61949
62089
 
@@ -62013,6 +62153,7 @@ class Composer extends Component {
62013
62153
  showDescription: false,
62014
62154
  functionDescription: {},
62015
62155
  argsToFocus: [],
62156
+ repeatingArgGroupIndex: 0,
62016
62157
  });
62017
62158
  assistant = useState({
62018
62159
  forcedClosed: false,
@@ -62551,9 +62692,21 @@ class Composer extends Component {
62551
62692
  const isParenthesisClosed = this.props.composerStore.currentTokens.some((t) => t.type === "RIGHT_PAREN" && t.parenthesesCode === token.parenthesesCode);
62552
62693
  this.functionDescriptionState.argsToFocus = this.getArgsToFocus(isParenthesisClosed, description, nbrArgSupplied, argPosition);
62553
62694
  this.functionDescriptionState.showDescription = true;
62695
+ this.functionDescriptionState.repeatingArgGroupIndex = this.getRepeatingArgGroupIndex(description, nbrArgSupplied, argPosition);
62554
62696
  }
62555
62697
  }
62556
62698
  }
62699
+ getRepeatingArgGroupIndex(description, nbrArgSupplied, argPosition) {
62700
+ const { minArgRequired, maxArgPossible, nbrArgRepeating } = description;
62701
+ if (!nbrArgRepeating) {
62702
+ return undefined;
62703
+ }
62704
+ const groupsOfOptionalRepeatingValues = nbrArgRepeating
62705
+ ? Math.ceil((nbrArgSupplied - minArgRequired) / nbrArgRepeating)
62706
+ : 0;
62707
+ const nbrArgSuppliedRoundedToGroupOfRepeating = groupsOfOptionalRepeatingValues * nbrArgRepeating + minArgRequired;
62708
+ return (argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSuppliedRoundedToGroupOfRepeating), minArgRequired))(argPosition).repeatingGroupIndex ?? 0);
62709
+ }
62557
62710
  /**
62558
62711
  * Compute the arguments to focus depending on the current value position.
62559
62712
  *
@@ -62563,11 +62716,11 @@ class Composer extends Component {
62563
62716
  * This function computes all the possible arguments to focus for different numbers of arguments supplied.
62564
62717
  */
62565
62718
  getArgsToFocus(isParenthesisClosed, description, nbrArgSupplied, argPosition) {
62566
- const { nbrArgRepeating, minArgRequired, nbrArgOptional, maxArgPossible } = description;
62719
+ const { nbrArgRepeating, minArgRequired, nbrOptionalNonRepeatingArgs, maxArgPossible } = description;
62567
62720
  // When the parenthesis is closed, we consider the user is done with the function,
62568
62721
  // so we know exactly the number of arguments supplied.
62569
62722
  if (isParenthesisClosed) {
62570
- const focusedArg = argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSupplied), minArgRequired))(argPosition);
62723
+ const focusedArg = argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSupplied), minArgRequired))(argPosition)?.index;
62571
62724
  return focusedArg !== undefined ? [focusedArg] : [];
62572
62725
  }
62573
62726
  // Otherwise, the user is still typing the formula, so we don't know yet how many arguments the user will supply.
@@ -62576,11 +62729,11 @@ class Composer extends Component {
62576
62729
  const maxArgsNumberPossibility = nbrArgRepeating
62577
62730
  ? minArgRequired +
62578
62731
  Math.ceil((minArgsNumberPossibility - minArgRequired) / nbrArgRepeating) * nbrArgRepeating +
62579
- nbrArgOptional
62732
+ nbrOptionalNonRepeatingArgs
62580
62733
  : maxArgPossible;
62581
62734
  const argsToFocus = [];
62582
62735
  for (let i = minArgsNumberPossibility; i <= maxArgsNumberPossibility; i++) {
62583
- const focusedArg = argTargeting(description, i)(argPosition);
62736
+ const focusedArg = argTargeting(description, i)(argPosition)?.index;
62584
62737
  if (focusedArg !== undefined) {
62585
62738
  argsToFocus.push(focusedArg);
62586
62739
  }
@@ -67485,6 +67638,17 @@ const irregularityMap = {
67485
67638
  isReadonlyAllowed: true,
67486
67639
  icon: "o-spreadsheet-Icon.IRREGULARITY_MAP",
67487
67640
  };
67641
+ function zoomAction(zoom) {
67642
+ return {
67643
+ name: _t$1("%(zoom_percentage)s%", { zoom_percentage: zoom }),
67644
+ execute: (env) => {
67645
+ env.model.dispatch("SET_ZOOM", { zoom: zoom / 100 });
67646
+ },
67647
+ isActive: (env) => env.model.getters.getViewportZoomLevel() === zoom / 100,
67648
+ isReadonlyAllowed: true,
67649
+ sequence: zoom,
67650
+ };
67651
+ }
67488
67652
  const viewFormulas = {
67489
67653
  name: _t$1("Formulas"),
67490
67654
  isActive: (env) => env.model.getters.shouldShowFormulas(),
@@ -69611,13 +69775,14 @@ function useDragAndDropBeyondTheViewport(env) {
69611
69775
  }
69612
69776
  const sheetId = getters.getActiveSheetId();
69613
69777
  const position = gridOverlayPosition();
69778
+ const zoomedMouseEvent = withZoom(env, currentEv, position);
69614
69779
  const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
69615
69780
  const { top, left, bottom, right } = getters.getActiveMainViewport();
69616
69781
  let { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
69617
69782
  const { xSplit, ySplit } = getters.getPaneDivisions(sheetId);
69618
69783
  let canEdgeScroll = false;
69619
69784
  let timeoutDelay = MAX_DELAY;
69620
- const x = currentEv.clientX - position.left;
69785
+ const x = zoomedMouseEvent.clientX - position.left;
69621
69786
  let colIndex = getters.getColIndex(x);
69622
69787
  if (scrollDirection !== "vertical") {
69623
69788
  const previousX = previousEvClientPosition.clientX - position.left;
@@ -69645,7 +69810,7 @@ function useDragAndDropBeyondTheViewport(env) {
69645
69810
  scrollX = getters.getColDimensions(sheetId, newTarget).start - offsetCorrectionX;
69646
69811
  }
69647
69812
  }
69648
- const y = currentEv.clientY - position.top;
69813
+ const y = zoomedMouseEvent.clientY - position.top;
69649
69814
  let rowIndex = getters.getRowIndex(y);
69650
69815
  if (scrollDirection !== "horizontal") {
69651
69816
  const previousY = previousEvClientPosition.clientY - position.top;
@@ -69685,7 +69850,10 @@ function useDragAndDropBeyondTheViewport(env) {
69685
69850
  pointerMoveHandler(currentEv);
69686
69851
  }, Math.round(timeoutDelay));
69687
69852
  }
69688
- previousEvClientPosition = { clientX: currentEv.clientX, clientY: currentEv.clientY };
69853
+ previousEvClientPosition = {
69854
+ clientX: zoomedMouseEvent.clientX,
69855
+ clientY: zoomedMouseEvent.clientY,
69856
+ };
69689
69857
  };
69690
69858
  const pointerUpHandler = () => {
69691
69859
  pointerUpCallback?.();
@@ -69727,30 +69895,30 @@ class Autofill extends Component {
69727
69895
  isVisible: Boolean,
69728
69896
  };
69729
69897
  state = useState({
69730
- position: { left: 0, top: 0 },
69898
+ position: { x: 0, y: 0 },
69731
69899
  handler: false,
69732
69900
  });
69733
69901
  dragNDropGrid = useDragAndDropBeyondTheViewport(this.env);
69734
69902
  get style() {
69735
- const { left, top } = this.props.position;
69903
+ const { x, y } = this.props.position;
69736
69904
  return cssPropertiesToCss({
69737
- top: `${top}px`,
69738
- left: `${left}px`,
69905
+ top: `${y}px`,
69906
+ left: `${x}px`,
69739
69907
  visibility: this.props.isVisible ? "visible" : "hidden",
69740
69908
  });
69741
69909
  }
69742
69910
  get handlerStyle() {
69743
- const { left, top } = this.state.handler ? this.state.position : this.props.position;
69911
+ const { x, y } = this.state.handler ? this.state.position : this.props.position;
69744
69912
  return cssPropertiesToCss({
69745
- top: `${top}px`,
69746
- left: `${left}px`,
69913
+ top: `${y}px`,
69914
+ left: `${x}px`,
69747
69915
  });
69748
69916
  }
69749
69917
  get styleNextValue() {
69750
- const { left, top } = this.state.position;
69918
+ const { x, y } = this.state.position;
69751
69919
  return cssPropertiesToCss({
69752
- top: `${top + 5}px`,
69753
- left: `${left + 15}px`,
69920
+ top: `${y + 5}px`,
69921
+ left: `${x + 15}px`,
69754
69922
  });
69755
69923
  }
69756
69924
  getTooltip() {
@@ -69762,11 +69930,13 @@ class Autofill extends Component {
69762
69930
  }
69763
69931
  onMouseDown(ev) {
69764
69932
  this.state.handler = true;
69933
+ const zoomedMouseEvent = withZoom(this.env, ev);
69934
+ const zoom = this.env.model.getters.getViewportZoomLevel();
69765
69935
  let lastCol;
69766
69936
  let lastRow;
69767
69937
  const start = {
69768
- left: ev.clientX - this.props.position.left,
69769
- top: ev.clientY - this.props.position.top,
69938
+ x: ev.clientX / zoom - this.props.position.x,
69939
+ y: ev.clientY / zoom - this.props.position.y,
69770
69940
  };
69771
69941
  const onMouseUp = () => {
69772
69942
  this.state.handler = false;
@@ -69775,8 +69945,8 @@ class Autofill extends Component {
69775
69945
  };
69776
69946
  const onMouseMove = (col, row, ev) => {
69777
69947
  this.state.position = {
69778
- left: ev.clientX - start.left,
69779
- top: ev.clientY - start.top,
69948
+ x: ev.clientX / zoom - start.x,
69949
+ y: ev.clientY / zoom - start.y,
69780
69950
  };
69781
69951
  if (lastCol !== col || lastRow !== row) {
69782
69952
  const activeSheetId = this.env.model.getters.getActiveSheetId();
@@ -69789,7 +69959,7 @@ class Autofill extends Component {
69789
69959
  }
69790
69960
  }
69791
69961
  };
69792
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
69962
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
69793
69963
  }
69794
69964
  onDblClick() {
69795
69965
  this.env.model.dispatch("AUTOFILL_AUTO");
@@ -70724,7 +70894,8 @@ class FiguresContainer extends Component {
70724
70894
  return;
70725
70895
  }
70726
70896
  const sheetId = this.env.model.getters.getActiveSheetId();
70727
- const initialMousePosition = { x: ev.clientX, y: ev.clientY };
70897
+ const zoom = this.env.model.getters.getViewportZoomLevel();
70898
+ const initialMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70728
70899
  const initialScrollPosition = this.env.model.getters.getActiveSheetScrollInfo();
70729
70900
  const initialFigure = this.toBottomRightViewport(figureUI);
70730
70901
  const maxDimensions = {
@@ -70734,7 +70905,7 @@ class FiguresContainer extends Component {
70734
70905
  let hasStartedDnd = false;
70735
70906
  const onMouseMove = (ev) => {
70736
70907
  const getters = this.env.model.getters;
70737
- const currentMousePosition = { x: ev.clientX, y: ev.clientY };
70908
+ const currentMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70738
70909
  const offsetX = Math.abs(currentMousePosition.x - initialMousePosition.x);
70739
70910
  const offsetY = Math.abs(currentMousePosition.y - initialMousePosition.y);
70740
70911
  if (!hasStartedDnd && offsetX < DRAG_THRESHOLD && offsetY < DRAG_THRESHOLD) {
@@ -70797,17 +70968,18 @@ class FiguresContainer extends Component {
70797
70968
  */
70798
70969
  startResize(figureUI, dirX, dirY, ev) {
70799
70970
  ev.stopPropagation();
70800
- const initialMousePosition = { x: ev.clientX, y: ev.clientY };
70801
70971
  const initialScrollPosition = this.env.model.getters.getActiveSheetScrollInfo();
70802
70972
  const keepRatio = figureRegistry.get(figureUI.tag).keepRatio || false;
70803
70973
  const minFigSize = figureRegistry.get(figureUI.tag).minFigSize || MIN_FIG_SIZE;
70974
+ const zoom = this.env.model.getters.getViewportZoomLevel();
70804
70975
  const sheetId = this.env.model.getters.getActiveSheetId();
70976
+ const initialMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70805
70977
  const maxDimensions = {
70806
70978
  maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
70807
70979
  maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
70808
70980
  };
70809
70981
  const onMouseMove = (ev) => {
70810
- const currentMousePosition = { x: ev.clientX, y: ev.clientY };
70982
+ const currentMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70811
70983
  const draggedFigure = dragFigureForResize(figureUI, dirX, dirY, currentMousePosition, initialMousePosition, keepRatio, minFigSize, initialScrollPosition, this.env.model.getters.getActiveSheetScrollInfo(), maxDimensions);
70812
70984
  const otherFigures = this.getOtherFigures(figureUI.id);
70813
70985
  const snapResult = snapForResize(this.env.model.getters, dirX, dirY, draggedFigure, otherFigures);
@@ -71219,11 +71391,11 @@ function useCellHovered(env, gridRef) {
71219
71391
  const row = env.model.getters.getRowIndex(y);
71220
71392
  return { col, row };
71221
71393
  }
71222
- function getOffsetRelativeToOverlay(ev) {
71394
+ function getOffsetRelativeToOverlay(zoomedMouseEvent) {
71223
71395
  const gridRect = getBoundingRectAsPOJO(gridRef.el);
71224
71396
  return {
71225
- x: ev.clientX - gridRect.x,
71226
- y: ev.clientY - gridRect.y,
71397
+ x: zoomedMouseEvent.clientX - gridRect.x,
71398
+ y: zoomedMouseEvent.clientY - gridRect.y,
71227
71399
  };
71228
71400
  }
71229
71401
  const { pause, resume } = useInterval(checkTiming, 200);
@@ -71240,9 +71412,9 @@ function useCellHovered(env, gridRef) {
71240
71412
  setPosition(col, row);
71241
71413
  }
71242
71414
  }
71243
- function updateMousePosition(e) {
71244
- if (isChildEvent(gridRef.el, e)) {
71245
- ({ x, y } = getOffsetRelativeToOverlay(e));
71415
+ function updateMousePosition(zoomedMouseEvent) {
71416
+ if (isChildEvent(gridRef.el, zoomedMouseEvent.ev)) {
71417
+ ({ x, y } = getOffsetRelativeToOverlay(zoomedMouseEvent));
71246
71418
  lastMoved = Date.now();
71247
71419
  hoveredTable.hover(getPosition());
71248
71420
  }
@@ -71254,20 +71426,21 @@ function useCellHovered(env, gridRef) {
71254
71426
  }
71255
71427
  }
71256
71428
  function onMouseLeave(e) {
71257
- const { x, y } = getOffsetRelativeToOverlay(e);
71429
+ const zoomedMouseEvent = withZoom(env, e);
71430
+ const { x, y } = getOffsetRelativeToOverlay(zoomedMouseEvent);
71258
71431
  const gridRect = getBoundingRectAsPOJO(gridRef.el);
71259
71432
  if (y < 0 || y > gridRect.height || x < 0 || x > gridRect.width) {
71260
- return updateMousePosition(e);
71433
+ return updateMousePosition(zoomedMouseEvent);
71261
71434
  }
71262
71435
  else {
71263
71436
  return pause();
71264
71437
  }
71265
71438
  }
71266
- useRefListener(gridRef, "pointermove", (ev) => !env.isMobile() && updateMousePosition(ev));
71439
+ useRefListener(gridRef, "pointermove", (ev) => !env.isMobile() && updateMousePosition(withZoom(env, ev)));
71267
71440
  useRefListener(gridRef, "mouseleave", onMouseLeave);
71268
71441
  useRefListener(gridRef, "mouseenter", resume);
71269
71442
  useRefListener(gridRef, "pointerdown", recompute);
71270
- useRefListener(gridRef, "pointerdown", (ev) => env.isMobile() && updateMousePosition(ev));
71443
+ useRefListener(gridRef, "pointerdown", (ev) => env.isMobile() && updateMousePosition(withZoom(env, ev)));
71271
71444
  useExternalListener(window, "click", handleGlobalClick);
71272
71445
  function handleGlobalClick(e) {
71273
71446
  const target = e.target;
@@ -71352,7 +71525,7 @@ class GridOverlay extends Component {
71352
71525
  if (this.env.isMobile()) {
71353
71526
  return;
71354
71527
  }
71355
- const icon = this.getInteractiveIconAtEvent(ev);
71528
+ const icon = this.getInteractiveIconAtEvent(withZoom(this.env, ev));
71356
71529
  const hoveredIcon = icon?.type ? { id: icon.type, position: icon.position } : undefined;
71357
71530
  if (!deepEquals$1(hoveredIcon, this.hoveredIconStore.hoveredIcon)) {
71358
71531
  this.hoveredIconStore.setHoveredIcon(hoveredIcon);
@@ -71363,30 +71536,30 @@ class GridOverlay extends Component {
71363
71536
  // not main button, probably a context menu
71364
71537
  return;
71365
71538
  }
71366
- this.onCellClicked(ev);
71539
+ this.onCellClicked(withZoom(this.env, ev));
71367
71540
  }
71368
71541
  onClick(ev) {
71369
71542
  if (ev.button > 0 || !this.env.isMobile()) {
71370
71543
  // not main button, probably a context menu
71371
71544
  return;
71372
71545
  }
71373
- this.onCellClicked(ev);
71546
+ this.onCellClicked(withZoom(this.env, ev));
71374
71547
  }
71375
- onCellClicked(ev) {
71548
+ onCellClicked(zoomedMouseEvent) {
71376
71549
  const openedPopover = this.cellPopovers.persistentCellPopover;
71377
- const [col, row] = this.getCartesianCoordinates(ev);
71378
- const clickedIcon = this.getInteractiveIconAtEvent(ev);
71550
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71551
+ const clickedIcon = this.getInteractiveIconAtEvent(zoomedMouseEvent);
71379
71552
  if (clickedIcon) {
71380
71553
  this.env.model.selection.getBackToDefault();
71381
71554
  }
71382
71555
  this.props.onCellClicked(col, row, {
71383
- expandZone: ev.shiftKey,
71384
- addZone: isCtrlKey(ev),
71385
- }, ev);
71556
+ expandZone: zoomedMouseEvent.ev.shiftKey,
71557
+ addZone: isCtrlKey(zoomedMouseEvent.ev),
71558
+ }, zoomedMouseEvent);
71386
71559
  if (clickedIcon?.onClick) {
71387
71560
  clickedIcon.onClick(clickedIcon.position, this.env);
71388
71561
  }
71389
- if (ev.target === this.gridOverlay.el &&
71562
+ if (zoomedMouseEvent.ev.target === this.gridOverlay.el &&
71390
71563
  this.cellPopovers.isOpen &&
71391
71564
  deepEquals$1(openedPopover, this.cellPopovers.persistentCellPopover)) {
71392
71565
  // Only close the popover if props.click/icon.click didn't open a new one
@@ -71395,30 +71568,28 @@ class GridOverlay extends Component {
71395
71568
  }
71396
71569
  }
71397
71570
  onDoubleClick(ev) {
71398
- if (this.getInteractiveIconAtEvent(ev)) {
71571
+ const zoomedMouseEvent = withZoom(this.env, ev);
71572
+ if (this.getInteractiveIconAtEvent(zoomedMouseEvent)) {
71399
71573
  return;
71400
71574
  }
71401
- const [col, row] = this.getCartesianCoordinates(ev);
71575
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71402
71576
  this.props.onCellDoubleClicked(col, row);
71403
71577
  }
71404
71578
  onContextMenu(ev) {
71405
- const [col, row] = this.getCartesianCoordinates(ev);
71579
+ const [col, row] = this.getCartesianCoordinates(withZoom(this.env, ev));
71406
71580
  this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
71407
71581
  }
71408
- getCartesianCoordinates(ev) {
71409
- const gridOverLayRect = getRefBoundingRect(this.gridOverlay);
71410
- const x = ev.clientX - gridOverLayRect.x;
71411
- const y = ev.clientY - gridOverLayRect.y;
71412
- const colIndex = this.env.model.getters.getColIndex(x);
71413
- const rowIndex = this.env.model.getters.getRowIndex(y);
71582
+ getCartesianCoordinates(zoomedMouseEvent) {
71583
+ const colIndex = this.env.model.getters.getColIndex(zoomedMouseEvent.offsetX);
71584
+ const rowIndex = this.env.model.getters.getRowIndex(zoomedMouseEvent.offsetY);
71414
71585
  return [colIndex, rowIndex];
71415
71586
  }
71416
- getInteractiveIconAtEvent(ev) {
71587
+ getInteractiveIconAtEvent(zoomedMouseEvent) {
71417
71588
  const gridOverLayRect = getRefBoundingRect(this.gridOverlay);
71418
71589
  const gridOffset = this.env.model.getters.getGridOffset();
71419
- const x = ev.clientX - gridOverLayRect.x + gridOffset.x;
71420
- const y = ev.clientY - gridOverLayRect.y + gridOffset.y;
71421
- const [col, row] = this.getCartesianCoordinates(ev);
71590
+ const x = zoomedMouseEvent.clientX - gridOverLayRect.x + gridOffset.x;
71591
+ const y = zoomedMouseEvent.clientY - gridOverLayRect.y + gridOffset.y;
71592
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71422
71593
  const sheetId = this.env.model.getters.getActiveSheetId();
71423
71594
  let position = { col, row, sheetId };
71424
71595
  const merge = this.env.model.getters.getMerge(position);
@@ -71453,7 +71624,8 @@ class GridPopover extends Component {
71453
71624
  if (!popover.isOpen) {
71454
71625
  return { isOpen: false };
71455
71626
  }
71456
- const anchorRect = popover.anchorRect;
71627
+ const zoom = this.env.model.getters.getViewportZoomLevel();
71628
+ const anchorRect = getZoomedRect(zoom, popover.anchorRect);
71457
71629
  return {
71458
71630
  ...popover,
71459
71631
  // transform from the "canvas coordinate system" to the "body coordinate system"
@@ -71558,8 +71730,8 @@ class AbstractResizer extends Component {
71558
71730
  setup() {
71559
71731
  this.composerFocusStore = useStore(ComposerFocusStore);
71560
71732
  }
71561
- _computeHandleDisplay(ev) {
71562
- const position = this._getEvOffset(ev);
71733
+ _computeHandleDisplay(zoomedMouseEvent) {
71734
+ const position = this._getEvOffset(zoomedMouseEvent);
71563
71735
  const elementIndex = this._getElementIndex(position);
71564
71736
  if (elementIndex < 0) {
71565
71737
  return;
@@ -71579,8 +71751,8 @@ class AbstractResizer extends Component {
71579
71751
  this.state.resizerIsActive = false;
71580
71752
  }
71581
71753
  }
71582
- _computeGrabDisplay(ev) {
71583
- const index = this._getElementIndex(this._getEvOffset(ev));
71754
+ _computeGrabDisplay(zoomedMouseEvent) {
71755
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71584
71756
  const activeElements = this._getActiveElements();
71585
71757
  const selectedZoneStart = this._getSelectedZoneStart();
71586
71758
  const selectedZoneEnd = this._getSelectedZoneEnd();
@@ -71596,26 +71768,29 @@ class AbstractResizer extends Component {
71596
71768
  if (this.env.isMobile()) {
71597
71769
  return;
71598
71770
  }
71771
+ const zoomedMouseEvent = withZoom(this.env, ev);
71599
71772
  if (this.state.isResizing || this.state.isMoving || this.state.isSelecting) {
71600
71773
  return;
71601
71774
  }
71602
- this._computeHandleDisplay(ev);
71603
- this._computeGrabDisplay(ev);
71775
+ this._computeHandleDisplay(zoomedMouseEvent);
71776
+ this._computeGrabDisplay(zoomedMouseEvent);
71604
71777
  }
71605
71778
  onMouseLeave() {
71606
71779
  this.state.resizerIsActive = this.state.isResizing;
71607
71780
  this.state.waitingForMove = false;
71608
71781
  }
71609
71782
  onDblClick(ev) {
71783
+ const zoomedMouseEvent = withZoom(this.env, ev);
71610
71784
  this._fitElementSize(this.state.activeElement);
71611
71785
  this.state.isResizing = false;
71612
- this._computeHandleDisplay(ev);
71613
- this._computeGrabDisplay(ev);
71786
+ this._computeHandleDisplay(zoomedMouseEvent);
71787
+ this._computeGrabDisplay(zoomedMouseEvent);
71614
71788
  }
71615
71789
  onMouseDown(ev) {
71616
71790
  this.state.isResizing = true;
71617
71791
  this.state.delta = 0;
71618
- const initialPosition = this._getClientPosition(ev);
71792
+ const zoomedMouseEvent = withZoom(this.env, ev);
71793
+ const initialPosition = this._getClientPosition(zoomedMouseEvent);
71619
71794
  const styleValue = this.state.draggerLinePosition;
71620
71795
  const size = this._getElementSize(this.state.activeElement);
71621
71796
  const minSize = styleValue - size + this.MIN_ELEMENT_SIZE;
@@ -71627,7 +71802,7 @@ class AbstractResizer extends Component {
71627
71802
  }
71628
71803
  };
71629
71804
  const onMouseMove = (ev) => {
71630
- this.state.delta = this._getClientPosition(ev) - initialPosition;
71805
+ this.state.delta = this._getClientPosition(withZoom(this.env, ev)) - initialPosition;
71631
71806
  this.state.draggerLinePosition = styleValue + this.state.delta;
71632
71807
  if (this.state.draggerLinePosition < minSize) {
71633
71808
  this.state.draggerLinePosition = minSize;
@@ -71648,7 +71823,8 @@ class AbstractResizer extends Component {
71648
71823
  // not main button, probably a context menu
71649
71824
  return;
71650
71825
  }
71651
- const index = this._getElementIndex(this._getEvOffset(ev));
71826
+ const zoomedMouseEvent = withZoom(this.env, ev);
71827
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71652
71828
  this._selectElement(index, false);
71653
71829
  }
71654
71830
  select(ev) {
@@ -71659,7 +71835,8 @@ class AbstractResizer extends Component {
71659
71835
  // not main button, probably a context menu
71660
71836
  return;
71661
71837
  }
71662
- const index = this._getElementIndex(this._getEvOffset(ev));
71838
+ const zoomedMouseEvent = withZoom(this.env, ev);
71839
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71663
71840
  if (index < 0) {
71664
71841
  return;
71665
71842
  }
@@ -71682,6 +71859,7 @@ class AbstractResizer extends Component {
71682
71859
  startMovement(ev) {
71683
71860
  this.state.waitingForMove = false;
71684
71861
  this.state.isMoving = true;
71862
+ const zoomedMouseEvent = withZoom(this.env, ev);
71685
71863
  const startDimensions = this._getDimensionsInViewport(this._getSelectedZoneStart());
71686
71864
  const endDimensions = this._getDimensionsInViewport(this._getSelectedZoneEnd());
71687
71865
  const defaultPosition = startDimensions.start;
@@ -71718,9 +71896,10 @@ class AbstractResizer extends Component {
71718
71896
  if (this.state.base !== this._getSelectedZoneStart()) {
71719
71897
  this._moveElements();
71720
71898
  }
71721
- this._computeGrabDisplay(ev);
71899
+ const zoomedMouseEvent = withZoom(this.env, ev);
71900
+ this._computeGrabDisplay(zoomedMouseEvent);
71722
71901
  };
71723
- this.dragNDropGrid.start(ev, mouseMoveMovement, mouseUpMovement);
71902
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMoveMovement, mouseUpMovement);
71724
71903
  }
71725
71904
  startSelection(ev, index) {
71726
71905
  if (this.env.isMobile()) {
@@ -71734,6 +71913,7 @@ class AbstractResizer extends Component {
71734
71913
  this._selectElement(index, isCtrlKey(ev));
71735
71914
  }
71736
71915
  this.lastSelectedElementIndex = index;
71916
+ const zoomedMouseEvent = withZoom(this.env, ev);
71737
71917
  const mouseMoveSelect = (col, row) => {
71738
71918
  const newIndex = this._getType() === "COL" ? col : row;
71739
71919
  if (newIndex !== this.lastSelectedElementIndex && newIndex !== -1) {
@@ -71744,16 +71924,16 @@ class AbstractResizer extends Component {
71744
71924
  const mouseUpSelect = () => {
71745
71925
  this.state.isSelecting = false;
71746
71926
  this.lastSelectedElementIndex = null;
71747
- this._computeGrabDisplay(ev);
71927
+ this._computeGrabDisplay(zoomedMouseEvent);
71748
71928
  };
71749
- this.dragNDropGrid.start(ev, mouseMoveSelect, mouseUpSelect);
71929
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMoveSelect, mouseUpSelect);
71750
71930
  }
71751
71931
  onMouseUp(ev) {
71752
71932
  this.lastSelectedElementIndex = null;
71753
71933
  }
71754
71934
  onContextMenu(ev) {
71755
71935
  ev.preventDefault();
71756
- const index = this._getElementIndex(this._getEvOffset(ev));
71936
+ const index = this._getElementIndex(this._getEvOffset(withZoom(this.env, ev)));
71757
71937
  if (index < 0)
71758
71938
  return;
71759
71939
  if (!this._getActiveElements().has(index)) {
@@ -71780,14 +71960,14 @@ class ColResizer extends AbstractResizer {
71780
71960
  get sheetId() {
71781
71961
  return this.env.model.getters.getActiveSheetId();
71782
71962
  }
71783
- _getEvOffset(ev) {
71784
- return ev.offsetX;
71963
+ _getEvOffset(zoomedMouseEvent) {
71964
+ return zoomedMouseEvent.offsetX;
71785
71965
  }
71786
71966
  _getViewportOffset() {
71787
71967
  return this.env.model.getters.getActiveMainViewport().left;
71788
71968
  }
71789
- _getClientPosition(ev) {
71790
- return ev.clientX;
71969
+ _getClientPosition(zoomedMouseEvent) {
71970
+ return zoomedMouseEvent.clientX;
71791
71971
  }
71792
71972
  _getElementIndex(position) {
71793
71973
  return this.env.model.getters.getColIndex(position);
@@ -71922,14 +72102,14 @@ class RowResizer extends AbstractResizer {
71922
72102
  get sheetId() {
71923
72103
  return this.env.model.getters.getActiveSheetId();
71924
72104
  }
71925
- _getEvOffset(ev) {
71926
- return ev.offsetY;
72105
+ _getEvOffset(zoomedMouseEvent) {
72106
+ return zoomedMouseEvent.offsetY;
71927
72107
  }
71928
72108
  _getViewportOffset() {
71929
72109
  return this.env.model.getters.getActiveMainViewport().top;
71930
72110
  }
71931
- _getClientPosition(ev) {
71932
- return ev.clientY;
72111
+ _getClientPosition(zoomedMouseEvent) {
72112
+ return zoomedMouseEvent.clientY;
71933
72113
  }
71934
72114
  _getElementIndex(position) {
71935
72115
  return this.env.model.getters.getRowIndex(position);
@@ -72878,18 +73058,21 @@ function useGridDrawing(refName, model, canvasSize) {
72878
73058
  const canvas = canvasRef.el;
72879
73059
  const dpr = window.devicePixelRatio || 1;
72880
73060
  const ctx = canvas.getContext("2d", { alpha: false });
73061
+ const zoom = Math.max(model.getters.getViewportZoomLevel(), 1);
72881
73062
  const thinLineWidth = 0.4 * dpr;
72882
73063
  const renderingContext = {
72883
73064
  ctx,
72884
73065
  dpr,
72885
73066
  thinLineWidth,
72886
73067
  };
72887
- const { width, height } = canvasSize();
73068
+ let { width, height } = canvasSize();
73069
+ width = zoom * width;
73070
+ height = zoom * height;
72888
73071
  canvas.style.width = `${width}px`;
72889
73072
  canvas.style.height = `${height}px`;
72890
73073
  canvas.width = width * dpr;
72891
73074
  canvas.height = height * dpr;
72892
- canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
73075
+ canvas.setAttribute("style", `width:${width}px;height:${height}px;zoom:${1 / zoom}`);
72893
73076
  if (width === 0 || height === 0) {
72894
73077
  return;
72895
73078
  }
@@ -72900,7 +73083,7 @@ function useGridDrawing(refName, model, canvasSize) {
72900
73083
  // you need to shift the coordinates by 0.5 perpendicular to the line's direction.
72901
73084
  // http://diveintohtml5.info/canvas.html#pixel-madness
72902
73085
  ctx.translate(-CANVAS_SHIFT, -CANVAS_SHIFT);
72903
- ctx.scale(dpr, dpr);
73086
+ ctx.scale(dpr * zoom, dpr * zoom);
72904
73087
  rendererStore.draw(renderingContext);
72905
73088
  }
72906
73089
  }
@@ -73136,6 +73319,7 @@ class Highlight extends Component {
73136
73319
  }
73137
73320
  onResizeHighlight(ev, dirX, dirY) {
73138
73321
  const activeSheetId = this.env.model.getters.getActiveSheetId();
73322
+ const zoomedMouseEvent = withZoom(this.env, ev);
73139
73323
  this.highlightState.shiftingMode = "isResizing";
73140
73324
  const z = this.props.range.zone;
73141
73325
  const pivotCol = dirX === 1 ? z.left : z.right;
@@ -73174,11 +73358,12 @@ class Highlight extends Component {
73174
73358
  const mouseUp = () => {
73175
73359
  this.highlightState.shiftingMode = "none";
73176
73360
  };
73177
- this.dragNDropGrid.start(ev, mouseMove, mouseUp, scrollDirection);
73361
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMove, mouseUp, scrollDirection);
73178
73362
  }
73179
73363
  onMoveHighlight(ev) {
73180
73364
  this.highlightState.shiftingMode = "isMoving";
73181
73365
  const z = this.props.range.zone;
73366
+ const zoomedMouseEvent = withZoom(this.env, ev);
73182
73367
  const position = gridOverlayPosition();
73183
73368
  const activeSheetId = this.env.model.getters.getActiveSheetId();
73184
73369
  const initCol = this.env.model.getters.getColIndex(ev.clientX - position.left);
@@ -73215,7 +73400,7 @@ class Highlight extends Component {
73215
73400
  const mouseUp = () => {
73216
73401
  this.highlightState.shiftingMode = "none";
73217
73402
  };
73218
- this.dragNDropGrid.start(ev, mouseMove, mouseUp);
73403
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMove, mouseUp);
73219
73404
  }
73220
73405
  }
73221
73406
 
@@ -73321,11 +73506,12 @@ class HorizontalScrollBar extends Component {
73321
73506
  }
73322
73507
  get position() {
73323
73508
  const { x } = this.env.model.getters.getMainViewportRect();
73509
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
73324
73510
  return {
73325
73511
  left: `${this.props.leftOffset + x}px`,
73326
73512
  bottom: "0px",
73327
- height: `${SCROLLBAR_WIDTH}px`,
73328
- right: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
73513
+ height: `${scrollbarWidth}px`,
73514
+ right: isBrowserFirefox() ? `${scrollbarWidth}px` : "0",
73329
73515
  };
73330
73516
  }
73331
73517
  onScroll(offset) {
@@ -73366,11 +73552,12 @@ class VerticalScrollBar extends Component {
73366
73552
  }
73367
73553
  get position() {
73368
73554
  const { y } = this.env.model.getters.getMainViewportRect();
73555
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
73369
73556
  return {
73370
73557
  top: `${this.props.topOffset + y}px`,
73371
73558
  right: "0px",
73372
- width: `${SCROLLBAR_WIDTH}px`,
73373
- bottom: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
73559
+ width: `${scrollbarWidth}px`,
73560
+ bottom: isBrowserFirefox() ? `${scrollbarWidth}px` : "0",
73374
73561
  };
73375
73562
  }
73376
73563
  onScroll(offset) {
@@ -73579,34 +73766,38 @@ class ColorPickerWidget extends Component {
73579
73766
  }
73580
73767
  }
73581
73768
 
73582
- class FontSizeEditor extends Component {
73583
- static template = "o-spreadsheet-FontSizeEditor";
73769
+ class NumberEditor extends Component {
73770
+ static template = "o-spreadsheet-NumberEditor";
73584
73771
  static props = {
73585
- currentFontSize: Number,
73586
- onFontSizeChanged: Function,
73772
+ currentValue: Number,
73773
+ onValueChange: Function,
73587
73774
  onToggle: { type: Function, optional: true },
73588
73775
  onFocusInput: { type: Function, optional: true },
73589
73776
  class: String,
73777
+ valueIcon: { type: String, optional: true },
73778
+ min: Number,
73779
+ max: Number,
73780
+ title: String,
73781
+ valueList: (Array),
73590
73782
  };
73591
73783
  static defaultProps = {
73592
73784
  onFocusInput: () => { },
73593
73785
  };
73594
73786
  static components = { Popover };
73595
- fontSizes = FONT_SIZES;
73596
73787
  dropdown = useState({ isOpen: false });
73597
- inputRef = useRef("inputFontSize");
73598
- rootEditorRef = useRef("FontSizeEditor");
73599
- fontSizeListRef = useRef("fontSizeList");
73788
+ inputRef = useRef("inputNumber");
73789
+ rootEditorRef = useRef("NumberEditor");
73790
+ valueListRef = useRef("numberList");
73600
73791
  setup() {
73601
73792
  useExternalListener(window, "click", this.onExternalClick, { capture: true });
73602
73793
  onWillUpdateProps((nextProps) => {
73603
73794
  if (this.inputRef.el && document.activeElement !== this.inputRef.el) {
73604
- this.inputRef.el.value = nextProps.currentFontSize;
73795
+ this.inputRef.el.value = nextProps.currentValue;
73605
73796
  }
73606
73797
  });
73607
73798
  onMounted(() => {
73608
73799
  if (this.inputRef.el) {
73609
- this.inputRef.el.value = this.props.currentFontSize.toString();
73800
+ this.inputRef.el.value = this.props.currentValue.toString();
73610
73801
  }
73611
73802
  });
73612
73803
  }
@@ -73619,33 +73810,36 @@ class FontSizeEditor extends Component {
73619
73810
  };
73620
73811
  }
73621
73812
  onExternalClick(ev) {
73622
- if (!isChildEvent(this.fontSizeListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
73623
- this.closeFontList();
73813
+ if (!isChildEvent(this.valueListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
73814
+ this.closeList();
73624
73815
  }
73625
73816
  }
73626
- toggleFontList() {
73817
+ toggleList() {
73627
73818
  const isOpen = this.dropdown.isOpen;
73628
73819
  if (!isOpen) {
73629
73820
  this.props.onToggle?.();
73630
73821
  this.inputRef.el.focus();
73631
73822
  }
73632
73823
  else {
73633
- this.closeFontList();
73824
+ this.closeList();
73634
73825
  }
73635
73826
  }
73636
- closeFontList() {
73827
+ closeList() {
73637
73828
  this.dropdown.isOpen = false;
73638
73829
  }
73639
- setSize(fontSizeStr) {
73640
- const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
73641
- this.props.onFontSizeChanged(fontSize);
73642
- this.closeFontList();
73830
+ setValue(valueStr) {
73831
+ const value = clip(Math.floor(parseFloat(valueStr)), this.props.min, this.props.max);
73832
+ this.props.onValueChange(value);
73833
+ this.closeList();
73834
+ }
73835
+ setValueFromInput(ev) {
73836
+ this.setValue(ev.target.value);
73643
73837
  }
73644
- setSizeFromInput(ev) {
73645
- this.setSize(ev.target.value);
73838
+ setValueFromList(valueStr) {
73839
+ this.setValue(valueStr);
73646
73840
  }
73647
- setSizeFromList(fontSizeStr) {
73648
- this.setSize(fontSizeStr);
73841
+ get currentValue() {
73842
+ return `${this.props.currentValue}`;
73649
73843
  }
73650
73844
  onInputFocused(ev) {
73651
73845
  this.dropdown.isOpen = true;
@@ -73653,17 +73847,33 @@ class FontSizeEditor extends Component {
73653
73847
  }
73654
73848
  onInputKeydown(ev) {
73655
73849
  if (ev.key === "Enter" || ev.key === "Escape") {
73656
- this.closeFontList();
73850
+ this.closeList();
73657
73851
  const target = ev.target;
73658
73852
  // In the case of a ESCAPE key, we get the previous font size back
73659
73853
  if (ev.key === "Escape") {
73660
- target.value = `${this.props.currentFontSize}`;
73854
+ target.value = `${this.props.currentValue}`;
73661
73855
  }
73662
73856
  this.props.onToggle?.();
73663
73857
  }
73664
73858
  }
73665
73859
  }
73666
73860
 
73861
+ class FontSizeEditor extends Component {
73862
+ static template = "o-spreadsheet-FontSizeEditor";
73863
+ static components = { NumberEditor };
73864
+ static props = {
73865
+ currentFontSize: Number,
73866
+ onFontSizeChanged: Function,
73867
+ onToggle: { type: Function, optional: true },
73868
+ onFocusInput: { type: Function, optional: true },
73869
+ class: String,
73870
+ };
73871
+ static defaultProps = {
73872
+ onFocusInput: () => { },
73873
+ };
73874
+ fontSizes = FONT_SIZES;
73875
+ }
73876
+
73667
73877
  class TextStyler extends Component {
73668
73878
  static template = "o-spreadsheet.TextStyler";
73669
73879
  static components = { ColorPickerWidget, ActionButton, FontSizeEditor };
@@ -80203,6 +80413,7 @@ class TableResizer extends Component {
80203
80413
  const tableZone = this.props.table.range.zone;
80204
80414
  const topLeft = { col: tableZone.left, row: tableZone.top };
80205
80415
  document.body.style.cursor = "nwse-resize";
80416
+ const zoomedMouseEvent = withZoom(this.env, ev);
80206
80417
  const onMouseUp = () => {
80207
80418
  document.body.style.cursor = "";
80208
80419
  const newTableZone = this.state.highlightZone;
@@ -80224,7 +80435,7 @@ class TableResizer extends Component {
80224
80435
  bottom: Math.max(row, topLeft.row),
80225
80436
  };
80226
80437
  };
80227
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
80438
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
80228
80439
  }
80229
80440
  get highlights() {
80230
80441
  if (!this.state.highlightZone)
@@ -80299,7 +80510,9 @@ class Grid extends Component {
80299
80510
  this.paintFormatStore = useStore(PaintFormatStore);
80300
80511
  this.clientFocusStore = useStore(ClientFocusStore);
80301
80512
  useStore(ArrayFormulaHighlight);
80302
- useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
80513
+ useChildSubEnv({
80514
+ getPopoverContainerRect: () => getZoomedRect(this.env.model.getters.getViewportZoomLevel(), this.getGridRect()),
80515
+ });
80303
80516
  useExternalListener(document.body, "cut", this.copy.bind(this, true));
80304
80517
  useExternalListener(document.body, "copy", this.copy.bind(this, false));
80305
80518
  useExternalListener(document.body, "paste", this.paste);
@@ -80325,11 +80538,12 @@ class Grid extends Component {
80325
80538
  return this.highlightStore.highlights;
80326
80539
  }
80327
80540
  get gridOverlayDimensions() {
80541
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
80328
80542
  return cssPropertiesToCss({
80329
80543
  top: `${HEADER_HEIGHT}px`,
80330
80544
  left: `${HEADER_WIDTH}px`,
80331
- height: `calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px)`,
80332
- width: `calc(100% - ${HEADER_WIDTH + SCROLLBAR_WIDTH}px)`,
80545
+ height: `calc(100% - ${HEADER_HEIGHT + scrollbarWidth}px)`,
80546
+ width: `calc(100% - ${HEADER_WIDTH + scrollbarWidth}px)`,
80333
80547
  });
80334
80548
  }
80335
80549
  onClosePopover() {
@@ -80535,8 +80749,8 @@ class Grid extends Component {
80535
80749
  const zone = this.env.model.getters.getSelectedZone();
80536
80750
  const rect = this.env.model.getters.getVisibleRect(zone);
80537
80751
  return {
80538
- left: rect.x + rect.width - AUTOFILL_EDGE_LENGTH / 2,
80539
- top: rect.y + rect.height - AUTOFILL_EDGE_LENGTH / 2,
80752
+ x: rect.x + rect.width - AUTOFILL_EDGE_LENGTH / 2,
80753
+ y: rect.y + rect.height - AUTOFILL_EDGE_LENGTH / 2,
80540
80754
  };
80541
80755
  }
80542
80756
  get isAutofillVisible() {
@@ -80592,8 +80806,8 @@ class Grid extends Component {
80592
80806
  // ---------------------------------------------------------------------------
80593
80807
  // Zone selection with mouse
80594
80808
  // ---------------------------------------------------------------------------
80595
- onCellClicked(col, row, modifiers, ev) {
80596
- ev.preventDefault();
80809
+ onCellClicked(col, row, modifiers, zoomedMouseEvent) {
80810
+ zoomedMouseEvent.ev.preventDefault();
80597
80811
  if (this.composerFocusStore.activeComposer.editionMode === "editing") {
80598
80812
  this.composerFocusStore.activeComposer.stopEdition();
80599
80813
  }
@@ -80627,7 +80841,7 @@ class Grid extends Component {
80627
80841
  this.paintFormatStore.pasteFormat(this.env.model.getters.getSelectedZones());
80628
80842
  }
80629
80843
  };
80630
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
80844
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
80631
80845
  }
80632
80846
  onCellDoubleClicked(col, row) {
80633
80847
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -82702,6 +82916,11 @@ topbarMenuRegistry
82702
82916
  .addChild("view_formulas", ["view", "show"], {
82703
82917
  ...viewFormulas,
82704
82918
  sequence: 10,
82919
+ })
82920
+ .addChild("zoom", ["view"], {
82921
+ name: _t$1("Zoom"),
82922
+ sequence: 1,
82923
+ icon: "o-spreadsheet-Icon.ZOOM",
82705
82924
  })
82706
82925
  .addChild("view_irregularity_map", ["view"], {
82707
82926
  ...irregularityMap,
@@ -82990,6 +83209,10 @@ topbarMenuRegistry
82990
83209
  })
82991
83210
  .addChild("reinsert_dynamic_pivot", ["data"], reinsertDynamicPivotMenu)
82992
83211
  .addChild("reinsert_static_pivot", ["data"], reinsertStaticPivotMenu);
83212
+ // Zoom
83213
+ ZOOM_VALUES.forEach((zoom) => {
83214
+ topbarMenuRegistry.addChild(`zoom${zoom}`, ["view", "zoom"], zoomAction(zoom));
83215
+ });
82993
83216
 
82994
83217
  const genericRepeatsTransforms = [
82995
83218
  repeatSheetDependantCommand,
@@ -84020,7 +84243,9 @@ class SpreadsheetDashboard extends Component {
84020
84243
  this.gridRef = useRef("grid");
84021
84244
  this.hoveredCell = useStore(DelayedHoveredCellStore);
84022
84245
  this.clickableCellsStore = useStore(ClickableCellsStore);
84023
- useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
84246
+ useChildSubEnv({
84247
+ getPopoverContainerRect: () => getZoomedRect(this.env.model.getters.getViewportZoomLevel(), this.getGridRect()),
84248
+ });
84024
84249
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimension());
84025
84250
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
84026
84251
  this.moveCanvas(deltaX, deltaY);
@@ -85086,6 +85311,35 @@ class NumberFormatsTool extends Component {
85086
85311
  }
85087
85312
  }
85088
85313
 
85314
+ class ToolBarZoom extends Component {
85315
+ static template = "o-spreadsheet-TopBarZoom";
85316
+ static components = { NumberEditor };
85317
+ static props = { class: String };
85318
+ topBarToolStore;
85319
+ valueList = ZOOM_VALUES;
85320
+ setup() {
85321
+ this.topBarToolStore = useToolBarDropdownStore();
85322
+ }
85323
+ get currentFontSize() {
85324
+ const zoom = this.env.model.getters.getViewportZoomLevel() || 1;
85325
+ return zoom * 100;
85326
+ }
85327
+ setZoom(fontSize) {
85328
+ this.env.model.dispatch("SET_ZOOM", { zoom: fontSize / 100 });
85329
+ }
85330
+ toggle() {
85331
+ if (this.topBarToolStore.isActive) {
85332
+ this.topBarToolStore.closeDropdowns();
85333
+ }
85334
+ else {
85335
+ this.topBarToolStore.openDropdown();
85336
+ }
85337
+ }
85338
+ onFocusInput() {
85339
+ this.topBarToolStore.openDropdown();
85340
+ }
85341
+ }
85342
+
85089
85343
  const topBarToolBarRegistry = new ToolBarRegistry();
85090
85344
  topBarToolBarRegistry
85091
85345
  .add("edit")
@@ -85119,6 +85373,13 @@ topBarToolBarRegistry
85119
85373
  class: "o-hoverable-button o-toolbar-button",
85120
85374
  },
85121
85375
  sequence: 4,
85376
+ })
85377
+ .addChild("edit", {
85378
+ component: ToolBarZoom,
85379
+ props: {
85380
+ class: "o-menu-item-button o-hoverable-button o-toolbar-button",
85381
+ },
85382
+ sequence: 5,
85122
85383
  })
85123
85384
  .add("numberFormat")
85124
85385
  .addChild("numberFormat", {
@@ -85585,6 +85846,7 @@ class Spreadsheet extends Component {
85585
85846
  }
85586
85847
  getStyle() {
85587
85848
  const properties = {};
85849
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
85588
85850
  if (this.env.isDashboard()) {
85589
85851
  properties["grid-template-rows"] = `auto`;
85590
85852
  }
@@ -85595,6 +85857,7 @@ class Spreadsheet extends Component {
85595
85857
  ? `${this.sidePanel.totalPanelSize || DEFAULT_SIDE_PANEL_SIZE}px`
85596
85858
  : "auto";
85597
85859
  properties["grid-template-columns"] = `auto ${columnWidth}`;
85860
+ properties["--os-scrollbar-width"] = `${scrollbarWidth}px`;
85598
85861
  return cssPropertiesToCss(properties);
85599
85862
  }
85600
85863
  setup() {
@@ -85723,9 +85986,11 @@ class Spreadsheet extends Component {
85723
85986
  get gridContainerStyle() {
85724
85987
  const gridColSize = GROUP_LAYER_WIDTH * this.rowLayers.length;
85725
85988
  const gridRowSize = GROUP_LAYER_WIDTH * this.colLayers.length;
85989
+ const zoom = this.env.model.getters.getViewportZoomLevel();
85726
85990
  return cssPropertiesToCss({
85727
85991
  "grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`, // +2: margins
85728
85992
  "grid-template-rows": `${gridRowSize ? gridRowSize + 2 : 0}px auto`,
85993
+ zoom: `${zoom}`,
85729
85994
  });
85730
85995
  }
85731
85996
  get rowLayers() {
@@ -85737,6 +86002,8 @@ class Spreadsheet extends Component {
85737
86002
  return this.env.model.getters.getVisibleGroupLayers(sheetId, "COL");
85738
86003
  }
85739
86004
  getGridSize() {
86005
+ const zoom = this.env.model.getters.getViewportZoomLevel();
86006
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
85740
86007
  const topBarHeight = this.spreadsheetRef.el
85741
86008
  ?.querySelector(".o-spreadsheet-topbar-wrapper")
85742
86009
  ?.getBoundingClientRect().height || 0;
@@ -85750,8 +86017,8 @@ class Spreadsheet extends Component {
85750
86017
  topBarHeight -
85751
86018
  bottomBarHeight;
85752
86019
  return {
85753
- width: Math.max(gridWidth - SCROLLBAR_WIDTH, 0),
85754
- height: Math.max(gridHeight - SCROLLBAR_WIDTH, 0),
86020
+ width: Math.max(gridWidth / zoom - scrollbarWidth, 0),
86021
+ height: Math.max(gridHeight / zoom - scrollbarWidth, 0),
85755
86022
  };
85756
86023
  }
85757
86024
  }
@@ -88250,6 +88517,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
88250
88517
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType$1 as CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DEFAULT_LOCALE, DEFAULT_LOCALES, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, categories, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, createAutocompleteArgumentsProvider, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
88251
88518
 
88252
88519
 
88253
- __info__.version = "19.1.0-alpha.10";
88254
- __info__.date = "2025-10-30T12:26:30.196Z";
88255
- __info__.hash = "d0b65e9";
88520
+ __info__.version = "19.1.0-alpha.11";
88521
+ __info__.date = "2025-11-03T12:34:28.925Z";
88522
+ __info__.hash = "d9230f3";