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

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.12
6
+ * @date 2025-11-12T14:17:07.713Z
7
+ * @hash 6fefc9c
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",
@@ -245,7 +247,7 @@ const DEFAULT_CAROUSEL_TITLE_STYLE = {
245
247
  fontSize: CHART_TITLE_FONT_SIZE,
246
248
  color: TEXT_BODY,
247
249
  };
248
- const DEFAULT_TOKEN_COLOR = "#000000";
250
+ const DEFAULT_TOKEN_COLOR = "light-dark(#000000, #ffffff)";
249
251
  const functionColor = DEFAULT_TOKEN_COLOR;
250
252
  const operatorColor = "#3da4ab";
251
253
  const tokenColors = {
@@ -1773,7 +1775,10 @@ function isInside(col, row, zone) {
1773
1775
  * Check if a zone is inside another
1774
1776
  */
1775
1777
  function isZoneInside(smallZone, biggerZone) {
1776
- return isEqual(union(biggerZone, smallZone), biggerZone);
1778
+ return (smallZone.left >= biggerZone.left &&
1779
+ smallZone.right <= biggerZone.right &&
1780
+ smallZone.top >= biggerZone.top &&
1781
+ smallZone.bottom <= biggerZone.bottom);
1777
1782
  }
1778
1783
  function zoneToDimension(zone) {
1779
1784
  return {
@@ -2285,13 +2290,13 @@ function addMetaInfoFromArg(name, addDescr) {
2285
2290
  let optionalArg = 0;
2286
2291
  for (const arg of addDescr.args) {
2287
2292
  countArg++;
2288
- if (!arg.optional && !arg.repeating && !arg.default) {
2293
+ if (!arg.optional && !arg.default) {
2289
2294
  minArg++;
2290
2295
  }
2291
2296
  if (arg.repeating) {
2292
2297
  repeatingArg++;
2293
2298
  }
2294
- if (arg.optional || arg.default) {
2299
+ if ((arg.optional || arg.default) && !arg.repeating) {
2295
2300
  optionalArg++;
2296
2301
  }
2297
2302
  }
@@ -2299,7 +2304,7 @@ function addMetaInfoFromArg(name, addDescr) {
2299
2304
  descr.minArgRequired = minArg;
2300
2305
  descr.maxArgPossible = repeatingArg ? Infinity : countArg;
2301
2306
  descr.nbrArgRepeating = repeatingArg;
2302
- descr.nbrArgOptional = optionalArg;
2307
+ descr.nbrOptionalNonRepeatingArgs = optionalArg;
2303
2308
  descr.hidden = addDescr.hidden || false;
2304
2309
  descr.name = name;
2305
2310
  return descr;
@@ -2327,9 +2332,9 @@ const cacheArgTargeting = {};
2327
2332
  * and rows representing the correspondence with the argument index.
2328
2333
  *
2329
2334
  * The tables are built based on the following conventions:
2330
- * - `m`: Mandatory argument
2331
- * - `o`: Optional argument
2332
- * - `r`: Repeating argument
2335
+ * - `m`: Mandatory argument (count as one argument)
2336
+ * - `o`: Optional argument (count as zero or one argument)
2337
+ * - `r`: Repeating argument (count as one or more arguments)
2333
2338
  *
2334
2339
  *
2335
2340
  * Configuration 1: (m, o) like the CEILING function
@@ -2342,39 +2347,39 @@ const cacheArgTargeting = {};
2342
2347
  *
2343
2348
  * Configuration 2: (m, m, m, r, r) like the SUMIFS function
2344
2349
  *
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 |
2350
+ * | | 5 | 7 | 3 + 2n |
2351
+ * |---|---|------|------------|
2352
+ * | m | 0 | 0 | 0 |
2353
+ * | m | 1 | 1 | 1 |
2354
+ * | m | 2 | 2 | 2 |
2355
+ * | r | 3 | 3, 5 | 3 + 2n |
2356
+ * | r | 4 | 4, 6 | 3 + 2n + 1 |
2352
2357
  *
2353
2358
  *
2354
2359
  * Configuration 3: (m, m, m, r, r, o) like the SWITCH function
2355
2360
  *
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 |
2361
+ * | | 5 | 6 | 7 | 8 | 3 + 2n | 3 + 2n + 1 |
2362
+ * |---|---|---|------|------|------------|----------------|
2363
+ * | m | 0 | 0 | 0 | 0 | 0 | 0 |
2364
+ * | m | 1 | 1 | 1 | 1 | 1 | 1 |
2365
+ * | m | 2 | 2 | 2 | 2 | 2 | 2 |
2366
+ * | r | 3 | 3 | 3, 5 | 3, 5 | 3 + 2n | 3 + 2n |
2367
+ * | r | 4 | 4 | 4, 6 | 4, 6 | 3 + 2n + 1 | 3 + 2n + 1 |
2368
+ * | o | | 5 | | 7 | | 3 + 2N + 2 |
2364
2369
  *
2365
2370
  *
2366
2371
  * Configuration 4: (m, o, m, o, r, r, r, m) a complex case to understand subtleties
2367
2372
  *
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 | ... |
2373
+ * | | 6 | 7 | 8 | 9 | 10 | 11 | ... |
2374
+ * |---|---|---|---|------|------|------|-----|
2375
+ * | m | 0 | 0 | 0 | 0 | 0 | 0 | ... |
2376
+ * | o | | 1 | 1 | | 1 | 1 | ... |
2377
+ * | m | 1 | 2 | 2 | 1 | 2 | 2 | ... |
2378
+ * | o | | | 3 | | | 3 | ... |
2379
+ * | r | 2 | 3 | 4 | 2, 5 | 3, 6 | 4, 7 | ... |
2380
+ * | r | 3 | 4 | 5 | 3, 6 | 4, 7 | 5, 8 | ... |
2381
+ * | r | 4 | 5 | 6 | 4, 7 | 5, 8 | 6, 9 | ... |
2382
+ * | m | 5 | 6 | 7 | 8 | 9 | 10 | ... |
2378
2383
  *
2379
2384
  */
2380
2385
  function argTargeting(functionDescription, nbrArgSupplied) {
@@ -2393,30 +2398,31 @@ function argTargeting(functionDescription, nbrArgSupplied) {
2393
2398
  }
2394
2399
  function _argTargeting(functionDescription, nbrArgSupplied) {
2395
2400
  const valueIndexToArgPosition = {};
2396
- const groupsOfRepeatingValues = functionDescription.nbrArgRepeating
2401
+ const groupsOfOptionalRepeatingValues = functionDescription.nbrArgRepeating
2397
2402
  ? Math.floor((nbrArgSupplied - functionDescription.minArgRequired) / functionDescription.nbrArgRepeating)
2398
2403
  : 0;
2399
- const nbrValueRepeating = functionDescription.nbrArgRepeating * groupsOfRepeatingValues;
2400
- const nbrValueOptional = nbrArgSupplied - functionDescription.minArgRequired - nbrValueRepeating;
2404
+ const nbrValueOptionalRepeating = functionDescription.nbrArgRepeating * groupsOfOptionalRepeatingValues;
2405
+ const nbrValueOptional = nbrArgSupplied - functionDescription.minArgRequired - nbrValueOptionalRepeating;
2401
2406
  let countValueSupplied = 0;
2402
2407
  let countValueOptional = 0;
2403
2408
  for (let i = 0; i < functionDescription.args.length; i++) {
2404
2409
  const arg = functionDescription.args[i];
2405
- if (arg.optional || arg.default) {
2410
+ if ((arg.optional || arg.default) && !arg.repeating) {
2406
2411
  if (countValueOptional < nbrValueOptional) {
2407
- valueIndexToArgPosition[countValueSupplied] = i;
2412
+ valueIndexToArgPosition[countValueSupplied] = { index: i };
2408
2413
  countValueSupplied++;
2409
2414
  }
2410
2415
  countValueOptional++;
2411
2416
  continue;
2412
2417
  }
2413
2418
  if (arg.repeating) {
2419
+ const groupOfMandatoryRepeatingValues = arg.optional ? 0 : 1;
2414
2420
  // As we know all repeating arguments are consecutive,
2415
2421
  // --> we will treat all repeating arguments in one go
2416
2422
  // --> 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++) {
2423
+ for (let j = 0; j < groupsOfOptionalRepeatingValues + groupOfMandatoryRepeatingValues; j++) {
2418
2424
  for (let k = 0; k < functionDescription.nbrArgRepeating; k++) {
2419
- valueIndexToArgPosition[countValueSupplied] = i + k;
2425
+ valueIndexToArgPosition[countValueSupplied] = { index: i + k, repeatingGroupIndex: j };
2420
2426
  countValueSupplied++;
2421
2427
  }
2422
2428
  }
@@ -2424,7 +2430,7 @@ function _argTargeting(functionDescription, nbrArgSupplied) {
2424
2430
  continue;
2425
2431
  }
2426
2432
  // End case: it's a required argument
2427
- valueIndexToArgPosition[countValueSupplied] = i;
2433
+ valueIndexToArgPosition[countValueSupplied] = { index: i };
2428
2434
  countValueSupplied++;
2429
2435
  }
2430
2436
  return (argPosition) => {
@@ -2436,7 +2442,7 @@ function _argTargeting(functionDescription, nbrArgSupplied) {
2436
2442
  //------------------------------------------------------------------------------
2437
2443
  const META_TYPES = ["META", "RANGE<META>"];
2438
2444
  function validateArguments(descr) {
2439
- if (descr.nbrArgRepeating && descr.nbrArgOptional >= descr.nbrArgRepeating) {
2445
+ if (descr.nbrArgRepeating && descr.nbrOptionalNonRepeatingArgs >= descr.nbrArgRepeating) {
2440
2446
  throw new Error(`Function ${descr.name} has more optional arguments than repeatable ones.`);
2441
2447
  }
2442
2448
  let foundRepeating = false;
@@ -4122,7 +4128,7 @@ function createComputeFunction(descr) {
4122
4128
  const getArgToFocus = argTargeting(descr, args.length);
4123
4129
  //#region Compute vectorisation limits
4124
4130
  for (let i = 0; i < args.length; i++) {
4125
- const argIndex = getArgToFocus(i) ?? -1;
4131
+ const argIndex = getArgToFocus(i).index ?? -1;
4126
4132
  const argDefinition = descr.args[argIndex];
4127
4133
  const arg = args[i];
4128
4134
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
@@ -4136,7 +4142,7 @@ function createComputeFunction(descr) {
4136
4142
  for (let i = 0; i < args.length; i++) {
4137
4143
  const arg = args[i];
4138
4144
  const getArgToFocus = argTargeting(descr, args.length);
4139
- const argDefinition = descr.args[getArgToFocus(i) || i];
4145
+ const argDefinition = descr.args[getArgToFocus(i).index ?? i];
4140
4146
  // Early exit if the argument is an error and the function does not accept errors
4141
4147
  // We only check scalar arguments, not matrix arguments for performance reasons.
4142
4148
  // Casting helpers are responsible for handling errors in matrix arguments.
@@ -4404,8 +4410,7 @@ const CHOOSECOLS = {
4404
4410
  description: _t$1("Creates a new array from the selected columns in the existing range."),
4405
4411
  args: [
4406
4412
  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.")),
4413
+ arg("col_num (number, range<number>, repeating)", _t$1("The column index of the column to be returned.")),
4409
4414
  ],
4410
4415
  compute: function (array, ...columns) {
4411
4416
  const _array = toMatrix(array);
@@ -4434,8 +4439,7 @@ const CHOOSEROWS = {
4434
4439
  description: _t$1("Creates a new array from the selected rows in the existing range."),
4435
4440
  args: [
4436
4441
  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.")),
4442
+ arg("row_num (number, range<number>, repeating)", _t$1("The row index of the row to be returned.")),
4439
4443
  ],
4440
4444
  compute: function (array, ...rows) {
4441
4445
  const _array = toMatrix(array);
@@ -4485,10 +4489,7 @@ const EXPAND = {
4485
4489
  // -----------------------------------------------------------------------------
4486
4490
  const FLATTEN = {
4487
4491
  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
- ],
4492
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to flatten."))],
4492
4493
  compute: function (...ranges) {
4493
4494
  return [flattenRowFirst(ranges, (val) => (val === undefined ? { value: "" } : val))];
4494
4495
  },
@@ -4546,10 +4547,7 @@ const FREQUENCY = {
4546
4547
  // -----------------------------------------------------------------------------
4547
4548
  const HSTACK = {
4548
4549
  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
- ],
4550
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to be appended."))],
4553
4551
  compute: function (...ranges) {
4554
4552
  const nbRows = Math.max(...ranges.map((r) => r?.[0]?.length ?? 0));
4555
4553
  const result = [];
@@ -4635,8 +4633,7 @@ const MMULT = {
4635
4633
  const SUMPRODUCT = {
4636
4634
  description: _t$1("Calculates the sum of the products of corresponding entries in equal-sized ranges."),
4637
4635
  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.")),
4636
+ arg("range (number, range<number>, repeating)", _t$1("The range whose entries will be multiplied with corresponding entries in the other range.")),
4640
4637
  ],
4641
4638
  compute: function (...args) {
4642
4639
  if (!areSameDimensions(...args)) {
@@ -4822,10 +4819,7 @@ const TRANSPOSE = {
4822
4819
  // -----------------------------------------------------------------------------
4823
4820
  const VSTACK = {
4824
4821
  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
- ],
4822
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to be appended."))],
4829
4823
  compute: function (...ranges) {
4830
4824
  const nbColumns = Math.max(...ranges.map((range) => toMatrix(range).length));
4831
4825
  const nbRows = ranges.reduce((acc, range) => acc + toMatrix(range)[0].length, 0);
@@ -6392,6 +6386,7 @@ const readonlyAllowedCommands = new Set([
6392
6386
  "COPY",
6393
6387
  "RESIZE_SHEETVIEW",
6394
6388
  "SET_VIEWPORT_OFFSET",
6389
+ "SET_ZOOM",
6395
6390
  "EVALUATE_CELLS",
6396
6391
  "EVALUATE_CHARTS",
6397
6392
  "SET_FORMULA_VISIBILITY",
@@ -7107,8 +7102,7 @@ const COTH = {
7107
7102
  const COUNTBLANK = {
7108
7103
  description: _t$1("Number of empty values."),
7109
7104
  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.")),
7105
+ arg("value (any, range, repeating)", _t$1("Value or range in which to count the number of blanks.")),
7112
7106
  ],
7113
7107
  compute: function (...args) {
7114
7108
  return reduceAny(args, (acc, a) => {
@@ -7150,10 +7144,8 @@ const COUNTIF = {
7150
7144
  const COUNTIFS = {
7151
7145
  description: _t$1("Count values depending on multiple criteria."),
7152
7146
  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.")),
7147
+ arg("criteria_range (any, range, repeating)", _t$1("Range over which to evaluate criteria.")),
7148
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7157
7149
  ],
7158
7150
  compute: function (...args) {
7159
7151
  let count = 0;
@@ -7169,10 +7161,7 @@ const COUNTIFS = {
7169
7161
  // -----------------------------------------------------------------------------
7170
7162
  const COUNTUNIQUE = {
7171
7163
  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
- ],
7164
+ args: [arg("value (any, range, repeating)", _t$1("Value or range to consider for uniqueness."))],
7176
7165
  compute: function (...args) {
7177
7166
  return countUnique(args);
7178
7167
  },
@@ -7184,10 +7173,8 @@ const COUNTUNIQUEIFS = {
7184
7173
  description: _t$1("Counts number of unique values in a range, filtered by a set of criteria."),
7185
7174
  args: [
7186
7175
  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.")),
7176
+ arg("criteria_range (any, range, repeating)", _t$1("Range over which to evaluate criteria.")),
7177
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7191
7178
  ],
7192
7179
  compute: function (range, ...args) {
7193
7180
  const uniqueValues = new Set();
@@ -7543,8 +7530,7 @@ const POWER = {
7543
7530
  const PRODUCT = {
7544
7531
  description: _t$1("Result of multiplying a series of numbers together."),
7545
7532
  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.")),
7533
+ arg("factor (number, range<number>, repeating)", _t$1("Number or range to calculate for the product.")),
7548
7534
  ],
7549
7535
  compute: function (...factors) {
7550
7536
  let count = 0;
@@ -7876,8 +7862,7 @@ const SUBTOTAL = {
7876
7862
  ...subtotalFunctionOptionsIncludeHiddenRows,
7877
7863
  ...subtotalFunctionOptionsExcludeHiddenRows,
7878
7864
  ]),
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.")),
7865
+ arg("ref (meta, range<meta>, repeating)", _t$1("Range or reference for which you want the subtotal.")),
7881
7866
  ],
7882
7867
  compute: function (functionCode, ...refs) {
7883
7868
  let code = toInteger(functionCode, this.locale);
@@ -7921,10 +7906,7 @@ const SUBTOTAL = {
7921
7906
  // -----------------------------------------------------------------------------
7922
7907
  const SUM = {
7923
7908
  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
- ],
7909
+ args: [arg("value (number, range<number>, repeating)", _t$1("Number or range to add together."))],
7928
7910
  compute: function (...values) {
7929
7911
  const v1 = values[0];
7930
7912
  return {
@@ -7966,10 +7948,8 @@ const SUMIFS = {
7966
7948
  description: _t$1("Sums a range depending on multiple criteria."),
7967
7949
  args: [
7968
7950
  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.")),
7951
+ arg("criteria_range (any, range, repeating)", _t$1("Range to check.")),
7952
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7973
7953
  ],
7974
7954
  compute: function (sumRange, ...criters) {
7975
7955
  let sum = 0;
@@ -8451,8 +8431,7 @@ function centile(data, percent, isInclusive, locale) {
8451
8431
  const AVEDEV = {
8452
8432
  description: _t$1("Average magnitude of deviations from mean."),
8453
8433
  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.")),
8434
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
8456
8435
  ],
8457
8436
  compute: function (...values) {
8458
8437
  let count = 0;
@@ -8474,8 +8453,7 @@ const AVEDEV = {
8474
8453
  const AVERAGE = {
8475
8454
  description: _t$1("Numerical average value in a dataset, ignoring text."),
8476
8455
  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.")),
8456
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the average value.")),
8479
8457
  ],
8480
8458
  compute: function (...values) {
8481
8459
  return {
@@ -8493,10 +8471,8 @@ const negativeWeightError = _t$1("[[FUNCTION_NAME]] expects the weight to be pos
8493
8471
  const AVERAGE_WEIGHTED = {
8494
8472
  description: _t$1("Weighted average."),
8495
8473
  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.")),
8474
+ arg("values (number, range<number>, repeating)", _t$1("Value to average.")),
8475
+ arg("weights (number, range<number>, repeating)", _t$1("Weight for each corresponding value.")),
8500
8476
  ],
8501
8477
  compute: function (...args) {
8502
8478
  let sum = 0;
@@ -8552,8 +8528,7 @@ const AVERAGE_WEIGHTED = {
8552
8528
  const AVERAGEA = {
8553
8529
  description: _t$1("Numerical average value in a dataset."),
8554
8530
  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.")),
8531
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the average value.")),
8557
8532
  ],
8558
8533
  compute: function (...args) {
8559
8534
  let count = 0;
@@ -8606,10 +8581,8 @@ const AVERAGEIFS = {
8606
8581
  description: _t$1("Average of values depending on multiple criteria."),
8607
8582
  args: [
8608
8583
  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.")),
8584
+ arg("criteria_range (any, range, repeating)", _t$1("Range to check.")),
8585
+ arg("criterion (string, repeating)", _t$1("Criterion to check.")),
8613
8586
  ],
8614
8587
  compute: function (averageRange, ...args) {
8615
8588
  const _averageRange = toMatrix(averageRange);
@@ -8635,8 +8608,7 @@ const AVERAGEIFS = {
8635
8608
  const COUNT = {
8636
8609
  description: _t$1("The number of numeric values in dataset."),
8637
8610
  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.")),
8611
+ arg("value (number, any, range<number>, repeating)", _t$1("Value or range to consider when counting.")),
8640
8612
  ],
8641
8613
  compute: function (...values) {
8642
8614
  return countNumbers(values, this.locale);
@@ -8648,10 +8620,7 @@ const COUNT = {
8648
8620
  // -----------------------------------------------------------------------------
8649
8621
  const COUNTA = {
8650
8622
  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
- ],
8623
+ args: [arg("value (any, range, repeating)", _t$1("Value or range to consider when counting."))],
8655
8624
  compute: function (...values) {
8656
8625
  return countAny(values);
8657
8626
  },
@@ -8884,8 +8853,7 @@ const MATTHEWS = {
8884
8853
  const MAX = {
8885
8854
  description: _t$1("Maximum value in a numeric dataset."),
8886
8855
  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.")),
8856
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the maximum value.")),
8889
8857
  ],
8890
8858
  compute: function (...values) {
8891
8859
  return max(values, this.locale);
@@ -8898,8 +8866,7 @@ const MAX = {
8898
8866
  const MAXA = {
8899
8867
  description: _t$1("Maximum numeric value in a dataset."),
8900
8868
  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.")),
8869
+ arg("value (any, range, repeating)", _t$1("Value or range to consider when calculating the maximum value.")),
8903
8870
  ],
8904
8871
  compute: function (...args) {
8905
8872
  const maxa = reduceNumbersTextAs0(args, (acc, a) => {
@@ -8916,10 +8883,8 @@ const MAXIFS = {
8916
8883
  description: _t$1("Returns the maximum value in a range of cells, filtered by a set of criteria."),
8917
8884
  args: [
8918
8885
  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.")),
8886
+ arg("criteria_range (any, range, repeating)", _t$1("Range to evaluate criteria.")),
8887
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
8923
8888
  ],
8924
8889
  compute: function (range, ...args) {
8925
8890
  let result = -Infinity;
@@ -8939,8 +8904,7 @@ const MAXIFS = {
8939
8904
  const MEDIAN = {
8940
8905
  description: _t$1("Median value in a numeric dataset."),
8941
8906
  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.")),
8907
+ arg("value (any, range, repeating)", _t$1("Value or range to consider when calculating the median value.")),
8944
8908
  ],
8945
8909
  compute: function (...values) {
8946
8910
  const data = [];
@@ -8960,8 +8924,7 @@ const MEDIAN = {
8960
8924
  const MIN = {
8961
8925
  description: _t$1("Minimum value in a numeric dataset."),
8962
8926
  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.")),
8927
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the minimum value.")),
8965
8928
  ],
8966
8929
  compute: function (...values) {
8967
8930
  return min(values, this.locale);
@@ -8974,8 +8937,7 @@ const MIN = {
8974
8937
  const MINA = {
8975
8938
  description: _t$1("Minimum numeric value in a dataset."),
8976
8939
  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.")),
8940
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the minimum value.")),
8979
8941
  ],
8980
8942
  compute: function (...args) {
8981
8943
  const mina = reduceNumbersTextAs0(args, (acc, a) => {
@@ -8992,10 +8954,8 @@ const MINIFS = {
8992
8954
  description: _t$1("Returns the minimum value in a range of cells, filtered by a set of criteria."),
8993
8955
  args: [
8994
8956
  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.")),
8957
+ arg("criteria_range (any, range, repeating)", _t$1("Range to evaluate criteria.")),
8958
+ arg("criterion (string, repeating)", _t$1("Criterion to check.")),
8999
8959
  ],
9000
8960
  compute: function (range, ...args) {
9001
8961
  let result = Infinity;
@@ -9336,8 +9296,7 @@ const SPEARMAN = {
9336
9296
  const STDEV = {
9337
9297
  description: _t$1("Standard deviation."),
9338
9298
  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.")),
9299
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9341
9300
  ],
9342
9301
  compute: function (...args) {
9343
9302
  return Math.sqrt(VAR.compute.bind(this)(...args));
@@ -9350,8 +9309,7 @@ const STDEV = {
9350
9309
  const STDEV_P = {
9351
9310
  description: _t$1("Standard deviation of entire population."),
9352
9311
  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.")),
9312
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9355
9313
  ],
9356
9314
  compute: function (...args) {
9357
9315
  return Math.sqrt(VAR_P.compute.bind(this)(...args));
@@ -9364,8 +9322,7 @@ const STDEV_P = {
9364
9322
  const STDEV_S = {
9365
9323
  description: _t$1("Standard deviation."),
9366
9324
  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.")),
9325
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9369
9326
  ],
9370
9327
  compute: function (...args) {
9371
9328
  return Math.sqrt(VAR_S.compute.bind(this)(...args));
@@ -9378,8 +9335,7 @@ const STDEV_S = {
9378
9335
  const STDEVA = {
9379
9336
  description: _t$1("Standard deviation of sample (text as 0)."),
9380
9337
  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.")),
9338
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9383
9339
  ],
9384
9340
  compute: function (...args) {
9385
9341
  return Math.sqrt(VARA.compute.bind(this)(...args));
@@ -9392,8 +9348,7 @@ const STDEVA = {
9392
9348
  const STDEVP = {
9393
9349
  description: _t$1("Standard deviation of entire population."),
9394
9350
  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.")),
9351
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9397
9352
  ],
9398
9353
  compute: function (...args) {
9399
9354
  return Math.sqrt(VARP.compute.bind(this)(...args));
@@ -9406,8 +9361,7 @@ const STDEVP = {
9406
9361
  const STDEVPA = {
9407
9362
  description: _t$1("Standard deviation of entire population (text as 0)."),
9408
9363
  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.")),
9364
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9411
9365
  ],
9412
9366
  compute: function (...args) {
9413
9367
  return Math.sqrt(VARPA.compute.bind(this)(...args));
@@ -9457,8 +9411,7 @@ const TREND = {
9457
9411
  const VAR = {
9458
9412
  description: _t$1("Variance."),
9459
9413
  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.")),
9414
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9462
9415
  ],
9463
9416
  compute: function (...args) {
9464
9417
  return variance(args, true, false, this.locale);
@@ -9471,8 +9424,7 @@ const VAR = {
9471
9424
  const VAR_P = {
9472
9425
  description: _t$1("Variance of entire population."),
9473
9426
  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.")),
9427
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9476
9428
  ],
9477
9429
  compute: function (...args) {
9478
9430
  return variance(args, false, false, this.locale);
@@ -9485,8 +9437,7 @@ const VAR_P = {
9485
9437
  const VAR_S = {
9486
9438
  description: _t$1("Variance."),
9487
9439
  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.")),
9440
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9490
9441
  ],
9491
9442
  compute: function (...args) {
9492
9443
  return variance(args, true, false, this.locale);
@@ -9499,8 +9450,7 @@ const VAR_S = {
9499
9450
  const VARA = {
9500
9451
  description: _t$1("Variance of sample (text as 0)."),
9501
9452
  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.")),
9453
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9504
9454
  ],
9505
9455
  compute: function (...args) {
9506
9456
  return variance(args, true, true, this.locale);
@@ -9513,8 +9463,7 @@ const VARA = {
9513
9463
  const VARP = {
9514
9464
  description: _t$1("Variance of entire population."),
9515
9465
  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.")),
9466
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9518
9467
  ],
9519
9468
  compute: function (...args) {
9520
9469
  return variance(args, false, false, this.locale);
@@ -9527,8 +9476,7 @@ const VARP = {
9527
9476
  const VARPA = {
9528
9477
  description: _t$1("Variance of entire population (text as 0)."),
9529
9478
  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.")),
9479
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9532
9480
  ],
9533
9481
  compute: function (...args) {
9534
9482
  return variance(args, false, true, this.locale);
@@ -11432,8 +11380,7 @@ const FILTER = {
11432
11380
  // TODO modify args description when vectorization on formulas is available
11433
11381
  args: [
11434
11382
  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.")),
11383
+ arg("condition (boolean, range<boolean>, repeating)", _t$1("Column or row containing true or false values corresponding to the range.")),
11437
11384
  ],
11438
11385
  compute: function (range, ...conditions) {
11439
11386
  let _array = toMatrix(range);
@@ -11473,8 +11420,8 @@ const SORT = {
11473
11420
  description: _t$1("Sorts the rows of a given array or range by the values in one or more columns."),
11474
11421
  args: [
11475
11422
  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."), [
11423
+ 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.")),
11424
+ 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
11425
  { value: true, label: _t$1("Ascending") },
11479
11426
  { value: false, label: _t$1("Descending") },
11480
11427
  ]),
@@ -11494,8 +11441,8 @@ const SORTN = {
11494
11441
  arg("range (range)", _t$1("The data to be sorted.")),
11495
11442
  arg("n (number)", _t$1("The number of items to return.")),
11496
11443
  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."), [
11444
+ 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.")),
11445
+ 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
11446
  { value: true, label: _t$1("Ascending") },
11500
11447
  { value: false, label: _t$1("Descending") },
11501
11448
  ]),
@@ -12763,8 +12710,7 @@ const NPV = {
12763
12710
  description: _t$1("The net present value of an investment based on a series of periodic cash flows and a discount rate."),
12764
12711
  args: [
12765
12712
  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.")),
12713
+ arg("cashflow (number, range<number>, repeating)", _t$1("The future cash flows.")),
12768
12714
  ],
12769
12715
  // to do: replace by dollar format
12770
12716
  compute: function (discount, ...values) {
@@ -14119,8 +14065,7 @@ function boolOr(args) {
14119
14065
  const AND = {
14120
14066
  description: _t$1("Logical `and` operator."),
14121
14067
  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.")),
14068
+ 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
14069
  ],
14125
14070
  compute: function (...logicalExpressions) {
14126
14071
  const { result, foundBoolean } = boolAnd(logicalExpressions);
@@ -14203,10 +14148,8 @@ const IFNA = {
14203
14148
  const IFS = {
14204
14149
  description: _t$1("Returns a value depending on multiple logical expressions."),
14205
14150
  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.")),
14151
+ 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.")),
14152
+ arg("value (any, range, repeating)", _t$1("The value to be returned if its corresponding condition is TRUE.")),
14210
14153
  ],
14211
14154
  compute: function (...values) {
14212
14155
  if (values.length % 2 !== 0) {
@@ -14245,8 +14188,7 @@ const NOT = {
14245
14188
  const OR = {
14246
14189
  description: _t$1("Logical `or` operator."),
14247
14190
  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.")),
14191
+ 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
14192
  ],
14251
14193
  compute: function (...logicalExpressions) {
14252
14194
  const { result, foundBoolean } = boolOr(logicalExpressions);
@@ -14264,10 +14206,8 @@ const SWITCH = {
14264
14206
  description: _t$1("Returns a value by comparing cases to an expression."),
14265
14207
  args: [
14266
14208
  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.")),
14209
+ arg("case (any, repeating)", _t$1("Case to be checked against expression.")),
14210
+ arg("value (any, repeating)", _t$1("Value to be returned if its corresponding case matches expression.")),
14271
14211
  arg(`default (any, default="empty")`, _t$1("An optional default value to be returned if none of the cases match expression.")),
14272
14212
  ],
14273
14213
  compute: function (expression, ...casesAndValues) {
@@ -14302,8 +14242,7 @@ const TRUE = {
14302
14242
  const XOR = {
14303
14243
  description: _t$1("Logical `xor` operator."),
14304
14244
  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.")),
14245
+ 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
14246
  ],
14308
14247
  compute: function (...logicalExpressions) {
14309
14248
  let foundBoolean = false;
@@ -15816,8 +15755,8 @@ const PIVOT_VALUE = {
15816
15755
  args: [
15817
15756
  arg("pivot_id (number,string)", _t$1("ID of the pivot.")),
15818
15757
  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.")),
15758
+ arg("domain_field_name (string,repeating,optional)", _t$1("Field name.")),
15759
+ arg("domain_value (number,string,boolean,repeating,optional)", _t$1("Value.")),
15821
15760
  ],
15822
15761
  compute: function (formulaId, measureName, ...domainArgs) {
15823
15762
  const _pivotFormulaId = toString(formulaId);
@@ -15852,8 +15791,8 @@ const PIVOT_HEADER = {
15852
15791
  description: _t$1("Get the header of a pivot."),
15853
15792
  args: [
15854
15793
  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.")),
15794
+ arg("domain_field_name (string,repeating,optional)", _t$1("Field name.")),
15795
+ arg("domain_value (number,string,value,repeating,optional)", _t$1("Value.")),
15857
15796
  ],
15858
15797
  compute: function (pivotId, ...domainArgs) {
15859
15798
  const _pivotFormulaId = toString(pivotId);
@@ -16724,10 +16663,7 @@ const CLEAN = {
16724
16663
  // -----------------------------------------------------------------------------
16725
16664
  const CONCATENATE = {
16726
16665
  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
- ],
16666
+ args: [arg("string (string, range<string>, repeating)", _t$1("String to append in sequence."))],
16731
16667
  compute: function (...datas) {
16732
16668
  return reduceAny(datas, (acc, a) => acc + toString(a), "");
16733
16669
  },
@@ -16782,8 +16718,7 @@ const JOIN = {
16782
16718
  description: _t$1("Concatenates elements of arrays with delimiter."),
16783
16719
  args: [
16784
16720
  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.")),
16721
+ arg("value_or_array (string, range<string>, repeating)", _t$1("Value to be appended using delimiter.")),
16787
16722
  ],
16788
16723
  compute: function (delimiter, ...valuesOrArrays) {
16789
16724
  const _delimiter = toString(delimiter);
@@ -17074,13 +17009,12 @@ const TEXTJOIN_DEFAULT_IGNORE_EMPTY = true;
17074
17009
  const TEXTJOIN = {
17075
17010
  description: _t$1("Combines text from multiple strings and/or arrays."),
17076
17011
  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.")),
17012
+ 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
17013
  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
17014
  { value: true, label: _t$1("Ignore empty cells") },
17080
17015
  { value: false, label: _t$1("Include empty cells (default)") },
17081
17016
  ]),
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).")),
17017
+ arg("texts (string, range<string>, repeating)", _t$1("Text item to join.")),
17084
17018
  ],
17085
17019
  compute: function (delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
17086
17020
  const _delimiter = toString(delimiter);
@@ -18458,12 +18392,10 @@ const colors = [
18458
18392
  "#00a3a3",
18459
18393
  "#f012be",
18460
18394
  "#3d9970",
18461
- "#111111",
18462
18395
  "#62A300",
18463
18396
  "#ff4136",
18464
18397
  "#949494",
18465
- "#85144b",
18466
- "#001f3f",
18398
+ "#ff5c9d",
18467
18399
  ];
18468
18400
  /*
18469
18401
  * transform a color number (R * 256^2 + G * 256 + B) into classic hex (+alpha) value
@@ -19488,7 +19420,7 @@ function getRangeString(range, forSheetId, getSheetName, options = { useBoundedR
19488
19420
  let sheetName = "";
19489
19421
  if (prefixSheet) {
19490
19422
  if (range.invalidSheetName) {
19491
- sheetName = range.invalidSheetName;
19423
+ sheetName = getCanonicalSymbolName(range.invalidSheetName);
19492
19424
  }
19493
19425
  else {
19494
19426
  sheetName = getCanonicalSymbolName(getSheetName(range.sheetId));
@@ -22465,7 +22397,7 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
22465
22397
  return {
22466
22398
  background: context.background,
22467
22399
  type: "scorecard",
22468
- keyValue: context.range ? context.range[0].dataRange : undefined,
22400
+ keyValue: context.range?.[0]?.dataRange,
22469
22401
  title: context.title || { text: "" },
22470
22402
  baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
22471
22403
  baselineColorUp: DEFAULT_SCORECARD_BASELINE_COLOR_UP,
@@ -22968,6 +22900,66 @@ class ScorecardChartConfigBuilder {
22968
22900
  }
22969
22901
  }
22970
22902
 
22903
+ /**
22904
+ * Return a POJO containing the original event as well as the client position and the client offset
22905
+ * where the event would target if the spreadsheet was not zoomed
22906
+ * @param ev unzoomed mouse event
22907
+ * @param originalTargetRect The original target bounding rect the resulting ZoomedMouseEvent offset must refer to
22908
+ * @returns a ZoomedMouseEvent
22909
+ */
22910
+ function withZoom(env, ev, originalTargetRect) {
22911
+ const zoomLevel = env.model.getters.getViewportZoomLevel();
22912
+ if (originalTargetRect === undefined) {
22913
+ originalTargetRect = getZoomTargetBoundingRect(ev);
22914
+ }
22915
+ if (!originalTargetRect)
22916
+ return withNoZoom(ev);
22917
+ const baseOffsetX = ev.clientX - originalTargetRect.left;
22918
+ const baseOffsetY = ev.clientY - originalTargetRect.top;
22919
+ const offsetX = baseOffsetX / zoomLevel;
22920
+ const offsetY = baseOffsetY / zoomLevel;
22921
+ return {
22922
+ ev,
22923
+ clientX: ev.clientX - baseOffsetX + offsetX,
22924
+ clientY: ev.clientY - baseOffsetY + offsetY,
22925
+ offsetX,
22926
+ offsetY,
22927
+ };
22928
+ }
22929
+ function withNoZoom(ev) {
22930
+ return {
22931
+ ev,
22932
+ clientX: ev.clientX,
22933
+ clientY: ev.clientY,
22934
+ offsetX: ev.offsetX,
22935
+ offsetY: ev.offsetY,
22936
+ };
22937
+ }
22938
+ /**
22939
+ * Return a Rect with position and size on the zoomed canvas
22940
+ */
22941
+ function getZoomedRect(zoom, rect) {
22942
+ return {
22943
+ height: rect.height * zoom,
22944
+ width: rect.width * zoom,
22945
+ x: rect.x * zoom,
22946
+ y: rect.y * zoom,
22947
+ };
22948
+ }
22949
+ /**
22950
+ * Returns the bounding rect of the closest or self element who is targetable by a ZoomedMouseEvent
22951
+ */
22952
+ function getZoomTargetBoundingRect(ev) {
22953
+ const target = ev.target;
22954
+ if (!target || !("classList" in target) || !(target instanceof Element)) {
22955
+ return null;
22956
+ }
22957
+ const targetEl = target.classList.contains("o-zoomable") ? target : target.closest(".o-zoomable");
22958
+ if (!targetEl)
22959
+ return null;
22960
+ return targetEl.getBoundingClientRect();
22961
+ }
22962
+
22971
22963
  class ScorecardChart extends Component {
22972
22964
  static template = "o-spreadsheet-ScorecardChart";
22973
22965
  static props = {
@@ -22991,7 +22983,8 @@ class ScorecardChart extends Component {
22991
22983
  }
22992
22984
  createChart() {
22993
22985
  const canvas = this.canvas.el;
22994
- const config = getScorecardConfiguration(canvas.getBoundingClientRect(), this.runtime);
22986
+ const zoom = this.env.model.getters.getViewportZoomLevel();
22987
+ const config = getScorecardConfiguration(getZoomedRect(1 / zoom, canvas.getBoundingClientRect()), this.runtime);
22995
22988
  drawScoreChart(config, canvas);
22996
22989
  }
22997
22990
  }
@@ -23110,8 +23103,7 @@ function isChildEvent(parent, ev) {
23110
23103
  function gridOverlayPosition() {
23111
23104
  const spreadsheetElement = document.querySelector(".o-grid-overlay");
23112
23105
  if (spreadsheetElement) {
23113
- const { top, left } = spreadsheetElement.getBoundingClientRect();
23114
- return { top, left };
23106
+ return spreadsheetElement.getBoundingClientRect();
23115
23107
  }
23116
23108
  throw new Error("Can't find spreadsheet position");
23117
23109
  }
@@ -23329,8 +23321,7 @@ function generateMasterChartConfig(chartJsConfig) {
23329
23321
  .filter((ds) => !isTrendLineAxis(ds["xAxisID"]))
23330
23322
  .map((ds) => ({
23331
23323
  ...ds,
23332
- pointRadius: 0,
23333
- showLine: true,
23324
+ pointRadius: ds.showLine === false ? 2 : 0, // Show points only for scatter plots
23334
23325
  })),
23335
23326
  },
23336
23327
  options: {
@@ -23893,9 +23884,13 @@ async function canvasToObjectUrl(canvas) {
23893
23884
  if (!blob) {
23894
23885
  return undefined;
23895
23886
  }
23896
- if (!URL.createObjectURL)
23897
- throw new Error("URL.createObjectURL is not supported in this environment");
23898
- return URL.createObjectURL(blob);
23887
+ return new Promise((resolve) => {
23888
+ const f = new FileReader();
23889
+ f.addEventListener("load", () => {
23890
+ resolve(f.result);
23891
+ });
23892
+ f.readAsDataURL(blob);
23893
+ });
23899
23894
  }
23900
23895
 
23901
23896
  /**
@@ -26253,7 +26248,7 @@ function compileTokensOrThrow(tokens) {
26253
26248
  const compiledArgs = [];
26254
26249
  const argToFocus = argTargeting(functionDefinition, args.length);
26255
26250
  for (let i = 0; i < args.length; i++) {
26256
- const argDefinition = functionDefinition.args[argToFocus(i) ?? -1];
26251
+ const argDefinition = functionDefinition.args[argToFocus(i).index ?? -1];
26257
26252
  const currentArg = args[i];
26258
26253
  const argTypes = argDefinition.type || [];
26259
26254
  // detect when an argument need to be evaluated as a meta argument
@@ -26432,12 +26427,15 @@ function assertEnoughArgs(ast) {
26432
26427
  }
26433
26428
  if (nbrArgRepeating > 1) {
26434
26429
  const nbrValueRepeating = nbrArgRepeating * Math.floor((nbrArgSupplied - minArgRequired) / nbrArgRepeating);
26435
- const nbrValueRemaining = nbrArgSupplied - minArgRequired - nbrValueRepeating - functionDefinition.nbrArgOptional;
26430
+ const nbrValueRemaining = nbrArgSupplied -
26431
+ minArgRequired -
26432
+ nbrValueRepeating -
26433
+ functionDefinition.nbrOptionalNonRepeatingArgs;
26436
26434
  if (nbrValueRemaining > 0) {
26437
26435
  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
26436
  functionName,
26439
26437
  nbrArgRepeating,
26440
- nbrArgOptional: functionDefinition.nbrArgOptional,
26438
+ nbrArgOptional: functionDefinition.nbrOptionalNonRepeatingArgs,
26441
26439
  nbrValueRemaining,
26442
26440
  }));
26443
26441
  }
@@ -44834,8 +44832,24 @@ function astToDoc(ast) {
44834
44832
  case "REFERENCE":
44835
44833
  return ast.value;
44836
44834
  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);
44835
+ const functionDescription = functionRegistry.get(ast.value.toUpperCase());
44836
+ const getArgToFocus = argTargeting(functionDescription, ast.args.length);
44837
+ const docs = [];
44838
+ let i = 0;
44839
+ while (i < ast.args.length) {
44840
+ const isRepeating = functionDescription.args[getArgToFocus(i).index ?? -1]?.repeating;
44841
+ if (isRepeating) {
44842
+ const repeatingArgSeries = ast.args.slice(i, i + functionDescription.nbrArgRepeating);
44843
+ const docsSeries = repeatingArgSeries.map((arg) => astToDoc(arg));
44844
+ docs.push(group(concat(splitArgsWithCommas(docsSeries))));
44845
+ i += functionDescription.nbrArgRepeating;
44846
+ }
44847
+ else {
44848
+ docs.push(astToDoc(ast.args[i]));
44849
+ i++;
44850
+ }
44851
+ }
44852
+ return wrapInParentheses(concat(splitArgsWithCommas(docs)), ast.value);
44839
44853
  case "UNARY_OPERATION":
44840
44854
  const operandDoc = astToDoc(ast.operand);
44841
44855
  const needParenthesis = ast.postfix
@@ -44861,6 +44875,14 @@ function astToDoc(ast) {
44861
44875
  return "";
44862
44876
  }
44863
44877
  }
44878
+ function splitArgsWithCommas(docs) {
44879
+ const result = docs.length ? [docs[0]] : [];
44880
+ for (let i = 1; i < docs.length; i++) {
44881
+ result.push(", ", line());
44882
+ result.push(docs[i]);
44883
+ }
44884
+ return result;
44885
+ }
44864
44886
  /**
44865
44887
  * Wraps a `Doc` in parentheses (with optional function name).
44866
44888
  */
@@ -46468,6 +46490,7 @@ pivotRegistry.add("SPREADSHEET", {
46468
46490
  isMeasureCandidate: (field) => field.type !== "boolean",
46469
46491
  isGroupable: () => true,
46470
46492
  canHaveCustomGroup: (field) => field.type === "char" && !field.isCustomField,
46493
+ isPivotUnused: () => true,
46471
46494
  });
46472
46495
 
46473
46496
  const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT", "REMOVE_PIVOT"];
@@ -46486,7 +46509,7 @@ class PivotUIPlugin extends CoreViewPlugin {
46486
46509
  "isSpillPivotFormula",
46487
46510
  ];
46488
46511
  pivots = {};
46489
- unusedPivots;
46512
+ unusedPivotsInFormulas;
46490
46513
  custom;
46491
46514
  constructor(config) {
46492
46515
  super(config);
@@ -46526,12 +46549,12 @@ class PivotUIPlugin extends CoreViewPlugin {
46526
46549
  }
46527
46550
  case "DELETE_SHEET":
46528
46551
  case "UPDATE_CELL": {
46529
- this.unusedPivots = undefined;
46552
+ this.unusedPivotsInFormulas = undefined;
46530
46553
  break;
46531
46554
  }
46532
46555
  case "UNDO":
46533
46556
  case "REDO": {
46534
- this.unusedPivots = undefined;
46557
+ this.unusedPivotsInFormulas = undefined;
46535
46558
  const pivotCommands = cmd.commands.filter(isPivotCommand);
46536
46559
  for (const cmd of pivotCommands) {
46537
46560
  const pivotId = cmd.pivotId;
@@ -46690,7 +46713,9 @@ class PivotUIPlugin extends CoreViewPlugin {
46690
46713
  return this.pivots[pivotId];
46691
46714
  }
46692
46715
  isPivotUnused(pivotId) {
46693
- return this._getUnusedPivots().includes(pivotId);
46716
+ const { type } = this.getters.getPivot(pivotId);
46717
+ return (this._getUnusedPivotsInFormulas().includes(pivotId) &&
46718
+ pivotRegistry.get(type).isPivotUnused(this.getters, pivotId));
46694
46719
  }
46695
46720
  getPivotCellSortDirection(position) {
46696
46721
  const pivotId = this.getters.getPivotIdFromPosition(position);
@@ -46726,9 +46751,9 @@ class PivotUIPlugin extends CoreViewPlugin {
46726
46751
  this.pivots[pivotId].onDefinitionChange(definition);
46727
46752
  }
46728
46753
  }
46729
- _getUnusedPivots() {
46730
- if (this.unusedPivots !== undefined) {
46731
- return this.unusedPivots;
46754
+ _getUnusedPivotsInFormulas() {
46755
+ if (this.unusedPivotsInFormulas !== undefined) {
46756
+ return this.unusedPivotsInFormulas;
46732
46757
  }
46733
46758
  const unusedPivots = new Set(this.getters.getPivotIds());
46734
46759
  for (const sheetId of this.getters.getSheetIds()) {
@@ -46738,14 +46763,14 @@ class PivotUIPlugin extends CoreViewPlugin {
46738
46763
  if (pivotId) {
46739
46764
  unusedPivots.delete(pivotId);
46740
46765
  if (!unusedPivots.size) {
46741
- this.unusedPivots = [];
46766
+ this.unusedPivotsInFormulas = [];
46742
46767
  return [];
46743
46768
  }
46744
46769
  }
46745
46770
  }
46746
46771
  }
46747
- this.unusedPivots = [...unusedPivots];
46748
- return this.unusedPivots;
46772
+ this.unusedPivotsInFormulas = [...unusedPivots];
46773
+ return this.unusedPivotsInFormulas;
46749
46774
  }
46750
46775
  }
46751
46776
 
@@ -52150,6 +52175,7 @@ class SheetViewPlugin extends UIPlugin {
52150
52175
  "getVisibleFigures",
52151
52176
  "getVisibleRect",
52152
52177
  "getVisibleRectWithoutHeaders",
52178
+ "getVisibleRectWithZoom",
52153
52179
  "getVisibleCellPositions",
52154
52180
  "getColRowOffsetInViewport",
52155
52181
  "getMainViewportCoordinates",
@@ -52165,6 +52191,8 @@ class SheetViewPlugin extends UIPlugin {
52165
52191
  "getFigureUI",
52166
52192
  "getPositionAnchorOffset",
52167
52193
  "getGridOffset",
52194
+ "getViewportZoomLevel",
52195
+ "getScrollBarWidth",
52168
52196
  ];
52169
52197
  viewports = {};
52170
52198
  /**
@@ -52177,6 +52205,7 @@ class SheetViewPlugin extends UIPlugin {
52177
52205
  sheetViewHeight = getDefaultSheetViewSize();
52178
52206
  gridOffsetX = 0;
52179
52207
  gridOffsetY = 0;
52208
+ zoomLevel = 1;
52180
52209
  sheetsWithDirtyViewports = new Set();
52181
52210
  shouldAdjustViewports = false;
52182
52211
  // ---------------------------------------------------------------------------
@@ -52243,6 +52272,9 @@ class SheetViewPlugin extends UIPlugin {
52243
52272
  case "SET_VIEWPORT_OFFSET":
52244
52273
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
52245
52274
  break;
52275
+ case "SET_ZOOM":
52276
+ this.zoomLevel = cmd.zoom || 1;
52277
+ break;
52246
52278
  case "SHIFT_VIEWPORT_DOWN":
52247
52279
  const sheetId = this.getters.getActiveSheetId();
52248
52280
  const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
@@ -52446,7 +52478,7 @@ class SheetViewPlugin extends UIPlugin {
52446
52478
  for (const i of relevantIndexes) {
52447
52479
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
52448
52480
  }
52449
- return offset;
52481
+ return offset * this.zoomLevel;
52450
52482
  }
52451
52483
  /**
52452
52484
  * Check if a given position is visible in the viewport.
@@ -52454,6 +52486,9 @@ class SheetViewPlugin extends UIPlugin {
52454
52486
  isVisibleInViewport({ sheetId, col, row }) {
52455
52487
  return this.getSubViewports(sheetId).some((pane) => pane.isVisible(col, row));
52456
52488
  }
52489
+ getScrollBarWidth() {
52490
+ return SCROLLBAR_WIDTH / this.zoomLevel;
52491
+ }
52457
52492
  // => returns the new offset
52458
52493
  getEdgeScrollCol(x, previousX, startingX) {
52459
52494
  let canEdgeScroll = false;
@@ -52532,6 +52567,18 @@ class SheetViewPlugin extends UIPlugin {
52532
52567
  const rect = this.getVisibleRectWithoutHeaders(zone);
52533
52568
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
52534
52569
  }
52570
+ /**
52571
+ * Computes the coordinates and size to draw the zone on the canvas after it has been zoomed
52572
+ */
52573
+ getVisibleRectWithZoom(zone) {
52574
+ const zoom = this.getViewportZoomLevel();
52575
+ const rect = this.getVisibleRectWithoutHeaders(zone);
52576
+ rect.width = rect.width * zoom;
52577
+ rect.height = rect.height * zoom;
52578
+ rect.x = rect.x * zoom + this.gridOffsetX * zoom;
52579
+ rect.y = rect.y * zoom + this.gridOffsetY * zoom;
52580
+ return rect;
52581
+ }
52535
52582
  /**
52536
52583
  * Computes the coordinates and size to draw the zone without taking the grid offset into account
52537
52584
  */
@@ -52613,6 +52660,9 @@ class SheetViewPlugin extends UIPlugin {
52613
52660
  };
52614
52661
  });
52615
52662
  }
52663
+ getViewportZoomLevel() {
52664
+ return this.zoomLevel;
52665
+ }
52616
52666
  // ---------------------------------------------------------------------------
52617
52667
  // Private
52618
52668
  // ---------------------------------------------------------------------------
@@ -56874,7 +56924,7 @@ class GaugeChart extends AbstractChart {
56874
56924
  background: context.background,
56875
56925
  title: context.title || { text: "" },
56876
56926
  type: "gauge",
56877
- dataRange: context.range ? context.range[0].dataRange : undefined,
56927
+ dataRange: context.range?.[0]?.dataRange,
56878
56928
  sectionRule: {
56879
56929
  colors: {
56880
56930
  lowerColor: DEFAULT_GAUGE_LOWER_COLOR,
@@ -58260,22 +58310,26 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58260
58310
  }
58261
58311
  onPointerDownInMasterChart(ev) {
58262
58312
  this.removeEventListeners();
58263
- const position = ev.offsetX;
58313
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58314
+ const position = zoomedEvent.offsetX;
58264
58315
  if (!this.masterChart?.chartArea || !this.chart?.scales?.x) {
58265
58316
  return;
58266
58317
  }
58267
58318
  const { left, right, top, bottom } = this.masterChart.chartArea;
58268
58319
  const xMax = this.upperBound ?? right;
58269
58320
  const xMin = this.lowerBound ?? left;
58270
- if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
58321
+ if (position < left - 5 ||
58322
+ position > right + 5 ||
58323
+ zoomedEvent.offsetY < top ||
58324
+ zoomedEvent.offsetY > bottom) {
58271
58325
  return;
58272
58326
  }
58273
58327
  ev.preventDefault();
58274
58328
  ev.stopPropagation();
58275
58329
  let startingPositionOnChart, windowSize, startX;
58276
- const startingEventPosition = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58330
+ const startingEventPosition = position;
58277
58331
  if ((xMin !== left || xMax !== right) && position > xMin + 5 && position < xMax - 5) {
58278
- startingPositionOnChart = ev.offsetX - xMin;
58332
+ startingPositionOnChart = zoomedEvent.offsetX - xMin;
58279
58333
  this.mode = "moveInMaster";
58280
58334
  const currentLimits = this.store.currentAxesLimits[this.chartId]?.x;
58281
58335
  windowSize =
@@ -58324,7 +58378,8 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58324
58378
  return { min: xMin, max: xMax };
58325
58379
  };
58326
58380
  const onDragFromMasterChart = (ev) => {
58327
- const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58381
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58382
+ const position = zoomedEvent.offsetX;
58328
58383
  if (Math.abs(position - startingEventPosition) < 5) {
58329
58384
  return;
58330
58385
  }
@@ -58335,7 +58390,8 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58335
58390
  };
58336
58391
  const onPointerUpInMasterChart = (ev) => {
58337
58392
  this.removeEventListeners();
58338
- const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58393
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58394
+ const position = zoomedEvent.offsetX;
58339
58395
  if (Math.abs(position - startingEventPosition) > 5) {
58340
58396
  let { min: xMin, max: xMax } = computeNewAxisLimits(position);
58341
58397
  if (xMin !== undefined && xMax !== undefined) {
@@ -58362,7 +58418,7 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58362
58418
  window.addEventListener("pointerup", onPointerUpInMasterChart, true);
58363
58419
  }
58364
58420
  onPointerMoveInMasterChart(ev) {
58365
- const { offsetX: x, offsetY: y } = ev;
58421
+ const { offsetX: x, offsetY: y } = withZoom(this.env, ev, ev.target?.getBoundingClientRect());
58366
58422
  if (this.mode === undefined) {
58367
58423
  const target = ev.target;
58368
58424
  if (!this.masterChart?.chartArea) {
@@ -58395,7 +58451,8 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58395
58451
  }
58396
58452
  onDoubleClickInMasterChart(ev) {
58397
58453
  this.mode = undefined;
58398
- const position = ev.offsetX;
58454
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58455
+ const position = zoomedEvent.offsetX;
58399
58456
  if (!this.masterChart?.chartArea || !this.chart?.scales.x) {
58400
58457
  return;
58401
58458
  }
@@ -58405,7 +58462,10 @@ class ZoomableChartJsComponent extends ChartJsComponent {
58405
58462
  if (upperBound < lowerBound) {
58406
58463
  [upperBound, lowerBound] = [lowerBound, upperBound];
58407
58464
  }
58408
- if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
58465
+ if (position < left - 5 ||
58466
+ position > right + 5 ||
58467
+ zoomedEvent.offsetY < top ||
58468
+ zoomedEvent.offsetY > bottom) {
58409
58469
  return;
58410
58470
  }
58411
58471
  ev.preventDefault();
@@ -58840,7 +58900,7 @@ class GaugeChartComponent extends Component {
58840
58900
  });
58841
58901
  }
58842
58902
  drawGaugeWithAnimation() {
58843
- drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue: 0 });
58903
+ drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue: 0 }, undefined);
58844
58904
  const gaugeValue = this.runtime.gaugeValue?.value || 0;
58845
58905
  const upperBound = this.runtime.maxValue.value;
58846
58906
  const finalValue = Math.sign(gaugeValue) * Math.min(Math.abs(gaugeValue), Math.abs(upperBound));
@@ -58848,7 +58908,7 @@ class GaugeChartComponent extends Component {
58848
58908
  return null;
58849
58909
  }
58850
58910
  const lowerBound = this.runtime.minValue.value;
58851
- const animation = new Animation(lowerBound, finalValue, ANIMATION_DURATION, (animationValue) => drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue }));
58911
+ const animation = new Animation(lowerBound, finalValue, ANIMATION_DURATION, (animationValue) => drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue }, undefined));
58852
58912
  animation.start();
58853
58913
  return animation;
58854
58914
  }
@@ -60068,7 +60128,13 @@ class FigureComponent extends Component {
60068
60128
  onContextMenu(ev) {
60069
60129
  if (this.env.isDashboard())
60070
60130
  return;
60071
- this.openContextMenu({ x: ev.clientX, y: ev.clientY, width: 0, height: 0 });
60131
+ const zoomedMouseEvent = withZoom(this.env, ev);
60132
+ this.openContextMenu({
60133
+ x: zoomedMouseEvent.clientX,
60134
+ y: zoomedMouseEvent.clientY,
60135
+ width: 0,
60136
+ height: 0,
60137
+ });
60072
60138
  }
60073
60139
  showMenu() {
60074
60140
  this.openContextMenu(getRefBoundingRect(this.menuButtonRef));
@@ -61668,7 +61734,7 @@ class TextValueProvider extends Component {
61668
61734
  }
61669
61735
  getCss(html) {
61670
61736
  return cssPropertiesToCss({
61671
- color: html.color || "#000000",
61737
+ color: html.color,
61672
61738
  background: html.backgroundColor,
61673
61739
  });
61674
61740
  }
@@ -61823,6 +61889,9 @@ class ContentEditableHelper {
61823
61889
  const span = document.createElement("span");
61824
61890
  span.innerText = content.value;
61825
61891
  span.style.color = content.color || "";
61892
+ if (content.opacity !== undefined && content.opacity !== 1) {
61893
+ span.style.opacity = content.opacity.toString();
61894
+ }
61826
61895
  span.addEventListener("mousemove", () => {
61827
61896
  content.onHover?.(getBoundingRectAsPOJO(span));
61828
61897
  });
@@ -61904,7 +61973,7 @@ class ContentEditableHelper {
61904
61973
  else {
61905
61974
  text += NEWLINE;
61906
61975
  }
61907
- emptyParagraph = ["<br>", "<span><br></span>"].includes(current.value.innerHTML);
61976
+ emptyParagraph = isEmptyParagraph(current.value);
61908
61977
  continue;
61909
61978
  }
61910
61979
  if (!current.value.hasChildNodes()) {
@@ -61918,12 +61987,29 @@ class ContentEditableHelper {
61918
61987
  }
61919
61988
  }
61920
61989
  function compareContentToSpanElement(content, node) {
61921
- const contentColor = content.color ? toHex(content.color) : "";
61922
- const nodeColor = node.style?.color ? toHex(node.style.color) : "";
61990
+ const contentColor = content.color || "";
61991
+ const nodeColor = node.style?.color || "";
61992
+ const nodeOpacity = node.style?.opacity || "1";
61923
61993
  const sameColor = contentColor === nodeColor;
61924
61994
  const sameClass = deepEquals$1(content.classes, [...node.classList]);
61925
61995
  const sameContent = node.innerText === content.value;
61926
- return sameColor && sameClass && sameContent;
61996
+ const sameOpacity = (content.opacity ?? 1).toString() === nodeOpacity;
61997
+ return sameColor && sameClass && sameContent && sameOpacity;
61998
+ }
61999
+ const doc = new DOMParser();
62000
+ const brNode = doc.parseFromString("<br>", "text/html").body.firstChild;
62001
+ const spanBrNode = doc.parseFromString("<span><br></span>", "text/html").body.firstChild;
62002
+ function isEmptyParagraph(node) {
62003
+ if (node.childNodes.length > 1)
62004
+ return false;
62005
+ const node2 = node.firstChild?.cloneNode(true);
62006
+ if (!node2)
62007
+ return true;
62008
+ if (!(node2 instanceof Element))
62009
+ return false;
62010
+ node2.removeAttribute("class");
62011
+ node2.removeAttribute("style");
62012
+ return node2.isEqualNode(brNode) || node2.isEqualNode(spanBrNode) || false;
61927
62013
  }
61928
62014
 
61929
62015
  class FunctionDescriptionProvider extends Component {
@@ -61931,6 +62017,7 @@ class FunctionDescriptionProvider extends Component {
61931
62017
  static props = {
61932
62018
  functionDescription: Object,
61933
62019
  argsToFocus: Array,
62020
+ repeatingArgGroupIndex: { type: Number, optional: true },
61934
62021
  };
61935
62022
  static components = { Collapse };
61936
62023
  state = useState({
@@ -61942,8 +62029,70 @@ class FunctionDescriptionProvider extends Component {
61942
62029
  getContext() {
61943
62030
  return this.props;
61944
62031
  }
61945
- get formulaArgSeparator() {
61946
- return this.env.model.getters.getLocale().formulaArgSeparator + " ";
62032
+ get formulaHeaderContent() {
62033
+ const { functionDescription, repeatingArgGroupIndex, argsToFocus } = this.props;
62034
+ const argSeparator = this.env.model.getters.getLocale().formulaArgSeparator + " ";
62035
+ const result = [
62036
+ { content: functionDescription.name + " ( " },
62037
+ ];
62038
+ for (let i = 0; i < functionDescription.args.length; i++) {
62039
+ const arg = functionDescription.args[i];
62040
+ const isRepeating = arg.repeating;
62041
+ if (i > 0) {
62042
+ result.push({ content: argSeparator });
62043
+ }
62044
+ if (isRepeating) {
62045
+ // treat all repeating args in one go
62046
+ const displayBrackets = arg.optional || (repeatingArgGroupIndex ?? 0) > 0;
62047
+ const repeatingArgNames = functionDescription.args
62048
+ .slice(i, i + functionDescription.nbrArgRepeating)
62049
+ .map((arg) => arg.name);
62050
+ if (repeatingArgGroupIndex) {
62051
+ result.push({ content: "... " + argSeparator });
62052
+ }
62053
+ if (displayBrackets) {
62054
+ result.push({ content: "[" });
62055
+ }
62056
+ for (let idx = 0; idx < repeatingArgNames.length; idx++) {
62057
+ const name = repeatingArgNames[idx];
62058
+ const argIndex = i + idx;
62059
+ const focused = argsToFocus.includes(argIndex);
62060
+ result.push({ content: name + ((repeatingArgGroupIndex ?? 0) + 1), focused });
62061
+ // Add separator after each element except the last
62062
+ if (idx < repeatingArgNames.length - 1) {
62063
+ result.push({ content: argSeparator });
62064
+ }
62065
+ }
62066
+ if (displayBrackets) {
62067
+ result.push({ content: "]" });
62068
+ }
62069
+ result.push({ content: argSeparator + "[" });
62070
+ for (let idx = 0; idx < repeatingArgNames.length; idx++) {
62071
+ const name = repeatingArgNames[idx];
62072
+ result.push({ content: name + ((repeatingArgGroupIndex ?? 0) + 2) });
62073
+ // Add separator after each element except the last
62074
+ if (idx < repeatingArgNames.length - 1) {
62075
+ result.push({ content: argSeparator });
62076
+ }
62077
+ }
62078
+ result.push({ content: "]" + argSeparator + "... " });
62079
+ // Skip the processed repeating args
62080
+ i += functionDescription.nbrArgRepeating - 1;
62081
+ }
62082
+ else {
62083
+ const displayBrackets = arg.optional || arg.default;
62084
+ const focused = argsToFocus.includes(i);
62085
+ if (displayBrackets) {
62086
+ result.push({ content: "[" });
62087
+ }
62088
+ result.push({ content: arg.name, focused });
62089
+ if (displayBrackets) {
62090
+ result.push({ content: "]" });
62091
+ }
62092
+ }
62093
+ }
62094
+ result.push({ content: " )" });
62095
+ return result;
61947
62096
  }
61948
62097
  }
61949
62098
 
@@ -62013,6 +62162,7 @@ class Composer extends Component {
62013
62162
  showDescription: false,
62014
62163
  functionDescription: {},
62015
62164
  argsToFocus: [],
62165
+ repeatingArgGroupIndex: 0,
62016
62166
  });
62017
62167
  assistant = useState({
62018
62168
  forcedClosed: false,
@@ -62450,10 +62600,6 @@ class Composer extends Component {
62450
62600
  const { end, start } = this.props.composerStore.composerSelection;
62451
62601
  for (let index = 0; index < tokens.length; index++) {
62452
62602
  const token = tokens[index];
62453
- let color = token.color || DEFAULT_TOKEN_COLOR;
62454
- if (token.isBlurred) {
62455
- color = setColorAlpha(color, 0.5);
62456
- }
62457
62603
  const classes = [];
62458
62604
  if (token.type === "REFERENCE" &&
62459
62605
  this.props.composerStore.tokenAtCursor === token &&
@@ -62471,7 +62617,8 @@ class Composer extends Component {
62471
62617
  }
62472
62618
  result.push({
62473
62619
  value: token.value,
62474
- color,
62620
+ color: token.color || DEFAULT_TOKEN_COLOR,
62621
+ opacity: token.isBlurred ? 0.5 : 1,
62475
62622
  classes,
62476
62623
  onHover: (rect) => this.onTokenHover(index, rect),
62477
62624
  onStopHover: () => this.onTokenHover(undefined),
@@ -62551,9 +62698,21 @@ class Composer extends Component {
62551
62698
  const isParenthesisClosed = this.props.composerStore.currentTokens.some((t) => t.type === "RIGHT_PAREN" && t.parenthesesCode === token.parenthesesCode);
62552
62699
  this.functionDescriptionState.argsToFocus = this.getArgsToFocus(isParenthesisClosed, description, nbrArgSupplied, argPosition);
62553
62700
  this.functionDescriptionState.showDescription = true;
62701
+ this.functionDescriptionState.repeatingArgGroupIndex = this.getRepeatingArgGroupIndex(description, nbrArgSupplied, argPosition);
62554
62702
  }
62555
62703
  }
62556
62704
  }
62705
+ getRepeatingArgGroupIndex(description, nbrArgSupplied, argPosition) {
62706
+ const { minArgRequired, maxArgPossible, nbrArgRepeating } = description;
62707
+ if (!nbrArgRepeating) {
62708
+ return undefined;
62709
+ }
62710
+ const groupsOfOptionalRepeatingValues = nbrArgRepeating
62711
+ ? Math.ceil((nbrArgSupplied - minArgRequired) / nbrArgRepeating)
62712
+ : 0;
62713
+ const nbrArgSuppliedRoundedToGroupOfRepeating = groupsOfOptionalRepeatingValues * nbrArgRepeating + minArgRequired;
62714
+ return (argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSuppliedRoundedToGroupOfRepeating), minArgRequired))(argPosition).repeatingGroupIndex ?? 0);
62715
+ }
62557
62716
  /**
62558
62717
  * Compute the arguments to focus depending on the current value position.
62559
62718
  *
@@ -62563,11 +62722,11 @@ class Composer extends Component {
62563
62722
  * This function computes all the possible arguments to focus for different numbers of arguments supplied.
62564
62723
  */
62565
62724
  getArgsToFocus(isParenthesisClosed, description, nbrArgSupplied, argPosition) {
62566
- const { nbrArgRepeating, minArgRequired, nbrArgOptional, maxArgPossible } = description;
62725
+ const { nbrArgRepeating, minArgRequired, nbrOptionalNonRepeatingArgs, maxArgPossible } = description;
62567
62726
  // When the parenthesis is closed, we consider the user is done with the function,
62568
62727
  // so we know exactly the number of arguments supplied.
62569
62728
  if (isParenthesisClosed) {
62570
- const focusedArg = argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSupplied), minArgRequired))(argPosition);
62729
+ const focusedArg = argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSupplied), minArgRequired))(argPosition)?.index;
62571
62730
  return focusedArg !== undefined ? [focusedArg] : [];
62572
62731
  }
62573
62732
  // Otherwise, the user is still typing the formula, so we don't know yet how many arguments the user will supply.
@@ -62576,11 +62735,11 @@ class Composer extends Component {
62576
62735
  const maxArgsNumberPossibility = nbrArgRepeating
62577
62736
  ? minArgRequired +
62578
62737
  Math.ceil((minArgsNumberPossibility - minArgRequired) / nbrArgRepeating) * nbrArgRepeating +
62579
- nbrArgOptional
62738
+ nbrOptionalNonRepeatingArgs
62580
62739
  : maxArgPossible;
62581
62740
  const argsToFocus = [];
62582
62741
  for (let i = minArgsNumberPossibility; i <= maxArgsNumberPossibility; i++) {
62583
- const focusedArg = argTargeting(description, i)(argPosition);
62742
+ const focusedArg = argTargeting(description, i)(argPosition)?.index;
62584
62743
  if (focusedArg !== undefined) {
62585
62744
  argsToFocus.push(focusedArg);
62586
62745
  }
@@ -63016,6 +63175,7 @@ class AbstractComposerStore extends SpreadsheetStore {
63016
63175
  this.highlightStore.register(this);
63017
63176
  this.onDispose(() => {
63018
63177
  this.highlightStore.unRegister(this);
63178
+ this._cancelEdition();
63019
63179
  });
63020
63180
  }
63021
63181
  handleEvent(event) {
@@ -67485,6 +67645,17 @@ const irregularityMap = {
67485
67645
  isReadonlyAllowed: true,
67486
67646
  icon: "o-spreadsheet-Icon.IRREGULARITY_MAP",
67487
67647
  };
67648
+ function zoomAction(zoom) {
67649
+ return {
67650
+ name: _t$1("%(zoom_percentage)s%", { zoom_percentage: zoom }),
67651
+ execute: (env) => {
67652
+ env.model.dispatch("SET_ZOOM", { zoom: zoom / 100 });
67653
+ },
67654
+ isActive: (env) => env.model.getters.getViewportZoomLevel() === zoom / 100,
67655
+ isReadonlyAllowed: true,
67656
+ sequence: zoom,
67657
+ };
67658
+ }
67488
67659
  const viewFormulas = {
67489
67660
  name: _t$1("Formulas"),
67490
67661
  isActive: (env) => env.model.getters.shouldShowFormulas(),
@@ -69611,13 +69782,14 @@ function useDragAndDropBeyondTheViewport(env) {
69611
69782
  }
69612
69783
  const sheetId = getters.getActiveSheetId();
69613
69784
  const position = gridOverlayPosition();
69785
+ const zoomedMouseEvent = withZoom(env, currentEv, position);
69614
69786
  const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
69615
69787
  const { top, left, bottom, right } = getters.getActiveMainViewport();
69616
69788
  let { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
69617
69789
  const { xSplit, ySplit } = getters.getPaneDivisions(sheetId);
69618
69790
  let canEdgeScroll = false;
69619
69791
  let timeoutDelay = MAX_DELAY;
69620
- const x = currentEv.clientX - position.left;
69792
+ const x = zoomedMouseEvent.clientX - position.left;
69621
69793
  let colIndex = getters.getColIndex(x);
69622
69794
  if (scrollDirection !== "vertical") {
69623
69795
  const previousX = previousEvClientPosition.clientX - position.left;
@@ -69645,7 +69817,7 @@ function useDragAndDropBeyondTheViewport(env) {
69645
69817
  scrollX = getters.getColDimensions(sheetId, newTarget).start - offsetCorrectionX;
69646
69818
  }
69647
69819
  }
69648
- const y = currentEv.clientY - position.top;
69820
+ const y = zoomedMouseEvent.clientY - position.top;
69649
69821
  let rowIndex = getters.getRowIndex(y);
69650
69822
  if (scrollDirection !== "horizontal") {
69651
69823
  const previousY = previousEvClientPosition.clientY - position.top;
@@ -69685,7 +69857,10 @@ function useDragAndDropBeyondTheViewport(env) {
69685
69857
  pointerMoveHandler(currentEv);
69686
69858
  }, Math.round(timeoutDelay));
69687
69859
  }
69688
- previousEvClientPosition = { clientX: currentEv.clientX, clientY: currentEv.clientY };
69860
+ previousEvClientPosition = {
69861
+ clientX: zoomedMouseEvent.clientX,
69862
+ clientY: zoomedMouseEvent.clientY,
69863
+ };
69689
69864
  };
69690
69865
  const pointerUpHandler = () => {
69691
69866
  pointerUpCallback?.();
@@ -69727,30 +69902,30 @@ class Autofill extends Component {
69727
69902
  isVisible: Boolean,
69728
69903
  };
69729
69904
  state = useState({
69730
- position: { left: 0, top: 0 },
69905
+ position: { x: 0, y: 0 },
69731
69906
  handler: false,
69732
69907
  });
69733
69908
  dragNDropGrid = useDragAndDropBeyondTheViewport(this.env);
69734
69909
  get style() {
69735
- const { left, top } = this.props.position;
69910
+ const { x, y } = this.props.position;
69736
69911
  return cssPropertiesToCss({
69737
- top: `${top}px`,
69738
- left: `${left}px`,
69912
+ top: `${y}px`,
69913
+ left: `${x}px`,
69739
69914
  visibility: this.props.isVisible ? "visible" : "hidden",
69740
69915
  });
69741
69916
  }
69742
69917
  get handlerStyle() {
69743
- const { left, top } = this.state.handler ? this.state.position : this.props.position;
69918
+ const { x, y } = this.state.handler ? this.state.position : this.props.position;
69744
69919
  return cssPropertiesToCss({
69745
- top: `${top}px`,
69746
- left: `${left}px`,
69920
+ top: `${y}px`,
69921
+ left: `${x}px`,
69747
69922
  });
69748
69923
  }
69749
69924
  get styleNextValue() {
69750
- const { left, top } = this.state.position;
69925
+ const { x, y } = this.state.position;
69751
69926
  return cssPropertiesToCss({
69752
- top: `${top + 5}px`,
69753
- left: `${left + 15}px`,
69927
+ top: `${y + 5}px`,
69928
+ left: `${x + 15}px`,
69754
69929
  });
69755
69930
  }
69756
69931
  getTooltip() {
@@ -69762,11 +69937,13 @@ class Autofill extends Component {
69762
69937
  }
69763
69938
  onMouseDown(ev) {
69764
69939
  this.state.handler = true;
69940
+ const zoomedMouseEvent = withZoom(this.env, ev);
69941
+ const zoom = this.env.model.getters.getViewportZoomLevel();
69765
69942
  let lastCol;
69766
69943
  let lastRow;
69767
69944
  const start = {
69768
- left: ev.clientX - this.props.position.left,
69769
- top: ev.clientY - this.props.position.top,
69945
+ x: ev.clientX / zoom - this.props.position.x,
69946
+ y: ev.clientY / zoom - this.props.position.y,
69770
69947
  };
69771
69948
  const onMouseUp = () => {
69772
69949
  this.state.handler = false;
@@ -69775,8 +69952,8 @@ class Autofill extends Component {
69775
69952
  };
69776
69953
  const onMouseMove = (col, row, ev) => {
69777
69954
  this.state.position = {
69778
- left: ev.clientX - start.left,
69779
- top: ev.clientY - start.top,
69955
+ x: ev.clientX / zoom - start.x,
69956
+ y: ev.clientY / zoom - start.y,
69780
69957
  };
69781
69958
  if (lastCol !== col || lastRow !== row) {
69782
69959
  const activeSheetId = this.env.model.getters.getActiveSheetId();
@@ -69789,7 +69966,7 @@ class Autofill extends Component {
69789
69966
  }
69790
69967
  }
69791
69968
  };
69792
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
69969
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
69793
69970
  }
69794
69971
  onDblClick() {
69795
69972
  this.env.model.dispatch("AUTOFILL_AUTO");
@@ -70724,7 +70901,8 @@ class FiguresContainer extends Component {
70724
70901
  return;
70725
70902
  }
70726
70903
  const sheetId = this.env.model.getters.getActiveSheetId();
70727
- const initialMousePosition = { x: ev.clientX, y: ev.clientY };
70904
+ const zoom = this.env.model.getters.getViewportZoomLevel();
70905
+ const initialMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70728
70906
  const initialScrollPosition = this.env.model.getters.getActiveSheetScrollInfo();
70729
70907
  const initialFigure = this.toBottomRightViewport(figureUI);
70730
70908
  const maxDimensions = {
@@ -70734,7 +70912,7 @@ class FiguresContainer extends Component {
70734
70912
  let hasStartedDnd = false;
70735
70913
  const onMouseMove = (ev) => {
70736
70914
  const getters = this.env.model.getters;
70737
- const currentMousePosition = { x: ev.clientX, y: ev.clientY };
70915
+ const currentMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70738
70916
  const offsetX = Math.abs(currentMousePosition.x - initialMousePosition.x);
70739
70917
  const offsetY = Math.abs(currentMousePosition.y - initialMousePosition.y);
70740
70918
  if (!hasStartedDnd && offsetX < DRAG_THRESHOLD && offsetY < DRAG_THRESHOLD) {
@@ -70797,17 +70975,18 @@ class FiguresContainer extends Component {
70797
70975
  */
70798
70976
  startResize(figureUI, dirX, dirY, ev) {
70799
70977
  ev.stopPropagation();
70800
- const initialMousePosition = { x: ev.clientX, y: ev.clientY };
70801
70978
  const initialScrollPosition = this.env.model.getters.getActiveSheetScrollInfo();
70802
70979
  const keepRatio = figureRegistry.get(figureUI.tag).keepRatio || false;
70803
70980
  const minFigSize = figureRegistry.get(figureUI.tag).minFigSize || MIN_FIG_SIZE;
70981
+ const zoom = this.env.model.getters.getViewportZoomLevel();
70804
70982
  const sheetId = this.env.model.getters.getActiveSheetId();
70983
+ const initialMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70805
70984
  const maxDimensions = {
70806
70985
  maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
70807
70986
  maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
70808
70987
  };
70809
70988
  const onMouseMove = (ev) => {
70810
- const currentMousePosition = { x: ev.clientX, y: ev.clientY };
70989
+ const currentMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70811
70990
  const draggedFigure = dragFigureForResize(figureUI, dirX, dirY, currentMousePosition, initialMousePosition, keepRatio, minFigSize, initialScrollPosition, this.env.model.getters.getActiveSheetScrollInfo(), maxDimensions);
70812
70991
  const otherFigures = this.getOtherFigures(figureUI.id);
70813
70992
  const snapResult = snapForResize(this.env.model.getters, dirX, dirY, draggedFigure, otherFigures);
@@ -71219,11 +71398,11 @@ function useCellHovered(env, gridRef) {
71219
71398
  const row = env.model.getters.getRowIndex(y);
71220
71399
  return { col, row };
71221
71400
  }
71222
- function getOffsetRelativeToOverlay(ev) {
71401
+ function getOffsetRelativeToOverlay(zoomedMouseEvent) {
71223
71402
  const gridRect = getBoundingRectAsPOJO(gridRef.el);
71224
71403
  return {
71225
- x: ev.clientX - gridRect.x,
71226
- y: ev.clientY - gridRect.y,
71404
+ x: zoomedMouseEvent.clientX - gridRect.x,
71405
+ y: zoomedMouseEvent.clientY - gridRect.y,
71227
71406
  };
71228
71407
  }
71229
71408
  const { pause, resume } = useInterval(checkTiming, 200);
@@ -71240,9 +71419,9 @@ function useCellHovered(env, gridRef) {
71240
71419
  setPosition(col, row);
71241
71420
  }
71242
71421
  }
71243
- function updateMousePosition(e) {
71244
- if (isChildEvent(gridRef.el, e)) {
71245
- ({ x, y } = getOffsetRelativeToOverlay(e));
71422
+ function updateMousePosition(zoomedMouseEvent) {
71423
+ if (isChildEvent(gridRef.el, zoomedMouseEvent.ev)) {
71424
+ ({ x, y } = getOffsetRelativeToOverlay(zoomedMouseEvent));
71246
71425
  lastMoved = Date.now();
71247
71426
  hoveredTable.hover(getPosition());
71248
71427
  }
@@ -71254,20 +71433,21 @@ function useCellHovered(env, gridRef) {
71254
71433
  }
71255
71434
  }
71256
71435
  function onMouseLeave(e) {
71257
- const { x, y } = getOffsetRelativeToOverlay(e);
71436
+ const zoomedMouseEvent = withZoom(env, e);
71437
+ const { x, y } = getOffsetRelativeToOverlay(zoomedMouseEvent);
71258
71438
  const gridRect = getBoundingRectAsPOJO(gridRef.el);
71259
71439
  if (y < 0 || y > gridRect.height || x < 0 || x > gridRect.width) {
71260
- return updateMousePosition(e);
71440
+ return updateMousePosition(zoomedMouseEvent);
71261
71441
  }
71262
71442
  else {
71263
71443
  return pause();
71264
71444
  }
71265
71445
  }
71266
- useRefListener(gridRef, "pointermove", (ev) => !env.isMobile() && updateMousePosition(ev));
71446
+ useRefListener(gridRef, "pointermove", (ev) => !env.isMobile() && updateMousePosition(withZoom(env, ev)));
71267
71447
  useRefListener(gridRef, "mouseleave", onMouseLeave);
71268
71448
  useRefListener(gridRef, "mouseenter", resume);
71269
71449
  useRefListener(gridRef, "pointerdown", recompute);
71270
- useRefListener(gridRef, "pointerdown", (ev) => env.isMobile() && updateMousePosition(ev));
71450
+ useRefListener(gridRef, "pointerdown", (ev) => env.isMobile() && updateMousePosition(withZoom(env, ev)));
71271
71451
  useExternalListener(window, "click", handleGlobalClick);
71272
71452
  function handleGlobalClick(e) {
71273
71453
  const target = e.target;
@@ -71352,7 +71532,7 @@ class GridOverlay extends Component {
71352
71532
  if (this.env.isMobile()) {
71353
71533
  return;
71354
71534
  }
71355
- const icon = this.getInteractiveIconAtEvent(ev);
71535
+ const icon = this.getInteractiveIconAtEvent(withZoom(this.env, ev));
71356
71536
  const hoveredIcon = icon?.type ? { id: icon.type, position: icon.position } : undefined;
71357
71537
  if (!deepEquals$1(hoveredIcon, this.hoveredIconStore.hoveredIcon)) {
71358
71538
  this.hoveredIconStore.setHoveredIcon(hoveredIcon);
@@ -71363,30 +71543,30 @@ class GridOverlay extends Component {
71363
71543
  // not main button, probably a context menu
71364
71544
  return;
71365
71545
  }
71366
- this.onCellClicked(ev);
71546
+ this.onCellClicked(withZoom(this.env, ev));
71367
71547
  }
71368
71548
  onClick(ev) {
71369
71549
  if (ev.button > 0 || !this.env.isMobile()) {
71370
71550
  // not main button, probably a context menu
71371
71551
  return;
71372
71552
  }
71373
- this.onCellClicked(ev);
71553
+ this.onCellClicked(withZoom(this.env, ev));
71374
71554
  }
71375
- onCellClicked(ev) {
71555
+ onCellClicked(zoomedMouseEvent) {
71376
71556
  const openedPopover = this.cellPopovers.persistentCellPopover;
71377
- const [col, row] = this.getCartesianCoordinates(ev);
71378
- const clickedIcon = this.getInteractiveIconAtEvent(ev);
71557
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71558
+ const clickedIcon = this.getInteractiveIconAtEvent(zoomedMouseEvent);
71379
71559
  if (clickedIcon) {
71380
71560
  this.env.model.selection.getBackToDefault();
71381
71561
  }
71382
71562
  this.props.onCellClicked(col, row, {
71383
- expandZone: ev.shiftKey,
71384
- addZone: isCtrlKey(ev),
71385
- }, ev);
71563
+ expandZone: zoomedMouseEvent.ev.shiftKey,
71564
+ addZone: isCtrlKey(zoomedMouseEvent.ev),
71565
+ }, zoomedMouseEvent);
71386
71566
  if (clickedIcon?.onClick) {
71387
71567
  clickedIcon.onClick(clickedIcon.position, this.env);
71388
71568
  }
71389
- if (ev.target === this.gridOverlay.el &&
71569
+ if (zoomedMouseEvent.ev.target === this.gridOverlay.el &&
71390
71570
  this.cellPopovers.isOpen &&
71391
71571
  deepEquals$1(openedPopover, this.cellPopovers.persistentCellPopover)) {
71392
71572
  // Only close the popover if props.click/icon.click didn't open a new one
@@ -71395,30 +71575,28 @@ class GridOverlay extends Component {
71395
71575
  }
71396
71576
  }
71397
71577
  onDoubleClick(ev) {
71398
- if (this.getInteractiveIconAtEvent(ev)) {
71578
+ const zoomedMouseEvent = withZoom(this.env, ev);
71579
+ if (this.getInteractiveIconAtEvent(zoomedMouseEvent)) {
71399
71580
  return;
71400
71581
  }
71401
- const [col, row] = this.getCartesianCoordinates(ev);
71582
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71402
71583
  this.props.onCellDoubleClicked(col, row);
71403
71584
  }
71404
71585
  onContextMenu(ev) {
71405
- const [col, row] = this.getCartesianCoordinates(ev);
71586
+ const [col, row] = this.getCartesianCoordinates(withZoom(this.env, ev));
71406
71587
  this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
71407
71588
  }
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);
71589
+ getCartesianCoordinates(zoomedMouseEvent) {
71590
+ const colIndex = this.env.model.getters.getColIndex(zoomedMouseEvent.offsetX);
71591
+ const rowIndex = this.env.model.getters.getRowIndex(zoomedMouseEvent.offsetY);
71414
71592
  return [colIndex, rowIndex];
71415
71593
  }
71416
- getInteractiveIconAtEvent(ev) {
71594
+ getInteractiveIconAtEvent(zoomedMouseEvent) {
71417
71595
  const gridOverLayRect = getRefBoundingRect(this.gridOverlay);
71418
71596
  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);
71597
+ const x = zoomedMouseEvent.clientX - gridOverLayRect.x + gridOffset.x;
71598
+ const y = zoomedMouseEvent.clientY - gridOverLayRect.y + gridOffset.y;
71599
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71422
71600
  const sheetId = this.env.model.getters.getActiveSheetId();
71423
71601
  let position = { col, row, sheetId };
71424
71602
  const merge = this.env.model.getters.getMerge(position);
@@ -71453,7 +71631,8 @@ class GridPopover extends Component {
71453
71631
  if (!popover.isOpen) {
71454
71632
  return { isOpen: false };
71455
71633
  }
71456
- const anchorRect = popover.anchorRect;
71634
+ const zoom = this.env.model.getters.getViewportZoomLevel();
71635
+ const anchorRect = getZoomedRect(zoom, popover.anchorRect);
71457
71636
  return {
71458
71637
  ...popover,
71459
71638
  // transform from the "canvas coordinate system" to the "body coordinate system"
@@ -71558,8 +71737,8 @@ class AbstractResizer extends Component {
71558
71737
  setup() {
71559
71738
  this.composerFocusStore = useStore(ComposerFocusStore);
71560
71739
  }
71561
- _computeHandleDisplay(ev) {
71562
- const position = this._getEvOffset(ev);
71740
+ _computeHandleDisplay(zoomedMouseEvent) {
71741
+ const position = this._getEvOffset(zoomedMouseEvent);
71563
71742
  const elementIndex = this._getElementIndex(position);
71564
71743
  if (elementIndex < 0) {
71565
71744
  return;
@@ -71579,8 +71758,8 @@ class AbstractResizer extends Component {
71579
71758
  this.state.resizerIsActive = false;
71580
71759
  }
71581
71760
  }
71582
- _computeGrabDisplay(ev) {
71583
- const index = this._getElementIndex(this._getEvOffset(ev));
71761
+ _computeGrabDisplay(zoomedMouseEvent) {
71762
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71584
71763
  const activeElements = this._getActiveElements();
71585
71764
  const selectedZoneStart = this._getSelectedZoneStart();
71586
71765
  const selectedZoneEnd = this._getSelectedZoneEnd();
@@ -71596,26 +71775,29 @@ class AbstractResizer extends Component {
71596
71775
  if (this.env.isMobile()) {
71597
71776
  return;
71598
71777
  }
71778
+ const zoomedMouseEvent = withZoom(this.env, ev);
71599
71779
  if (this.state.isResizing || this.state.isMoving || this.state.isSelecting) {
71600
71780
  return;
71601
71781
  }
71602
- this._computeHandleDisplay(ev);
71603
- this._computeGrabDisplay(ev);
71782
+ this._computeHandleDisplay(zoomedMouseEvent);
71783
+ this._computeGrabDisplay(zoomedMouseEvent);
71604
71784
  }
71605
71785
  onMouseLeave() {
71606
71786
  this.state.resizerIsActive = this.state.isResizing;
71607
71787
  this.state.waitingForMove = false;
71608
71788
  }
71609
71789
  onDblClick(ev) {
71790
+ const zoomedMouseEvent = withZoom(this.env, ev);
71610
71791
  this._fitElementSize(this.state.activeElement);
71611
71792
  this.state.isResizing = false;
71612
- this._computeHandleDisplay(ev);
71613
- this._computeGrabDisplay(ev);
71793
+ this._computeHandleDisplay(zoomedMouseEvent);
71794
+ this._computeGrabDisplay(zoomedMouseEvent);
71614
71795
  }
71615
71796
  onMouseDown(ev) {
71616
71797
  this.state.isResizing = true;
71617
71798
  this.state.delta = 0;
71618
- const initialPosition = this._getClientPosition(ev);
71799
+ const zoomedMouseEvent = withZoom(this.env, ev);
71800
+ const initialPosition = this._getClientPosition(zoomedMouseEvent);
71619
71801
  const styleValue = this.state.draggerLinePosition;
71620
71802
  const size = this._getElementSize(this.state.activeElement);
71621
71803
  const minSize = styleValue - size + this.MIN_ELEMENT_SIZE;
@@ -71627,7 +71809,7 @@ class AbstractResizer extends Component {
71627
71809
  }
71628
71810
  };
71629
71811
  const onMouseMove = (ev) => {
71630
- this.state.delta = this._getClientPosition(ev) - initialPosition;
71812
+ this.state.delta = this._getClientPosition(withZoom(this.env, ev)) - initialPosition;
71631
71813
  this.state.draggerLinePosition = styleValue + this.state.delta;
71632
71814
  if (this.state.draggerLinePosition < minSize) {
71633
71815
  this.state.draggerLinePosition = minSize;
@@ -71648,7 +71830,8 @@ class AbstractResizer extends Component {
71648
71830
  // not main button, probably a context menu
71649
71831
  return;
71650
71832
  }
71651
- const index = this._getElementIndex(this._getEvOffset(ev));
71833
+ const zoomedMouseEvent = withZoom(this.env, ev);
71834
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71652
71835
  this._selectElement(index, false);
71653
71836
  }
71654
71837
  select(ev) {
@@ -71659,7 +71842,8 @@ class AbstractResizer extends Component {
71659
71842
  // not main button, probably a context menu
71660
71843
  return;
71661
71844
  }
71662
- const index = this._getElementIndex(this._getEvOffset(ev));
71845
+ const zoomedMouseEvent = withZoom(this.env, ev);
71846
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71663
71847
  if (index < 0) {
71664
71848
  return;
71665
71849
  }
@@ -71682,6 +71866,7 @@ class AbstractResizer extends Component {
71682
71866
  startMovement(ev) {
71683
71867
  this.state.waitingForMove = false;
71684
71868
  this.state.isMoving = true;
71869
+ const zoomedMouseEvent = withZoom(this.env, ev);
71685
71870
  const startDimensions = this._getDimensionsInViewport(this._getSelectedZoneStart());
71686
71871
  const endDimensions = this._getDimensionsInViewport(this._getSelectedZoneEnd());
71687
71872
  const defaultPosition = startDimensions.start;
@@ -71718,9 +71903,10 @@ class AbstractResizer extends Component {
71718
71903
  if (this.state.base !== this._getSelectedZoneStart()) {
71719
71904
  this._moveElements();
71720
71905
  }
71721
- this._computeGrabDisplay(ev);
71906
+ const zoomedMouseEvent = withZoom(this.env, ev);
71907
+ this._computeGrabDisplay(zoomedMouseEvent);
71722
71908
  };
71723
- this.dragNDropGrid.start(ev, mouseMoveMovement, mouseUpMovement);
71909
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMoveMovement, mouseUpMovement);
71724
71910
  }
71725
71911
  startSelection(ev, index) {
71726
71912
  if (this.env.isMobile()) {
@@ -71734,6 +71920,7 @@ class AbstractResizer extends Component {
71734
71920
  this._selectElement(index, isCtrlKey(ev));
71735
71921
  }
71736
71922
  this.lastSelectedElementIndex = index;
71923
+ const zoomedMouseEvent = withZoom(this.env, ev);
71737
71924
  const mouseMoveSelect = (col, row) => {
71738
71925
  const newIndex = this._getType() === "COL" ? col : row;
71739
71926
  if (newIndex !== this.lastSelectedElementIndex && newIndex !== -1) {
@@ -71744,16 +71931,16 @@ class AbstractResizer extends Component {
71744
71931
  const mouseUpSelect = () => {
71745
71932
  this.state.isSelecting = false;
71746
71933
  this.lastSelectedElementIndex = null;
71747
- this._computeGrabDisplay(ev);
71934
+ this._computeGrabDisplay(zoomedMouseEvent);
71748
71935
  };
71749
- this.dragNDropGrid.start(ev, mouseMoveSelect, mouseUpSelect);
71936
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMoveSelect, mouseUpSelect);
71750
71937
  }
71751
71938
  onMouseUp(ev) {
71752
71939
  this.lastSelectedElementIndex = null;
71753
71940
  }
71754
71941
  onContextMenu(ev) {
71755
71942
  ev.preventDefault();
71756
- const index = this._getElementIndex(this._getEvOffset(ev));
71943
+ const index = this._getElementIndex(this._getEvOffset(withZoom(this.env, ev)));
71757
71944
  if (index < 0)
71758
71945
  return;
71759
71946
  if (!this._getActiveElements().has(index)) {
@@ -71780,14 +71967,14 @@ class ColResizer extends AbstractResizer {
71780
71967
  get sheetId() {
71781
71968
  return this.env.model.getters.getActiveSheetId();
71782
71969
  }
71783
- _getEvOffset(ev) {
71784
- return ev.offsetX;
71970
+ _getEvOffset(zoomedMouseEvent) {
71971
+ return zoomedMouseEvent.offsetX;
71785
71972
  }
71786
71973
  _getViewportOffset() {
71787
71974
  return this.env.model.getters.getActiveMainViewport().left;
71788
71975
  }
71789
- _getClientPosition(ev) {
71790
- return ev.clientX;
71976
+ _getClientPosition(zoomedMouseEvent) {
71977
+ return zoomedMouseEvent.clientX;
71791
71978
  }
71792
71979
  _getElementIndex(position) {
71793
71980
  return this.env.model.getters.getColIndex(position);
@@ -71922,14 +72109,14 @@ class RowResizer extends AbstractResizer {
71922
72109
  get sheetId() {
71923
72110
  return this.env.model.getters.getActiveSheetId();
71924
72111
  }
71925
- _getEvOffset(ev) {
71926
- return ev.offsetY;
72112
+ _getEvOffset(zoomedMouseEvent) {
72113
+ return zoomedMouseEvent.offsetY;
71927
72114
  }
71928
72115
  _getViewportOffset() {
71929
72116
  return this.env.model.getters.getActiveMainViewport().top;
71930
72117
  }
71931
- _getClientPosition(ev) {
71932
- return ev.clientY;
72118
+ _getClientPosition(zoomedMouseEvent) {
72119
+ return zoomedMouseEvent.clientY;
71933
72120
  }
71934
72121
  _getElementIndex(position) {
71935
72122
  return this.env.model.getters.getRowIndex(position);
@@ -72107,6 +72294,9 @@ class GridRenderer extends SpreadsheetStore {
72107
72294
  break;
72108
72295
  }
72109
72296
  }
72297
+ finalize() {
72298
+ this.zonesWithPreventedAnimationsInNextFrame = recomputeZones(this.zonesWithPreventedAnimationsInNextFrame);
72299
+ }
72110
72300
  get renderingLayers() {
72111
72301
  return ["Background", "Headers"];
72112
72302
  }
@@ -72878,18 +73068,21 @@ function useGridDrawing(refName, model, canvasSize) {
72878
73068
  const canvas = canvasRef.el;
72879
73069
  const dpr = window.devicePixelRatio || 1;
72880
73070
  const ctx = canvas.getContext("2d", { alpha: false });
73071
+ const zoom = Math.max(model.getters.getViewportZoomLevel(), 1);
72881
73072
  const thinLineWidth = 0.4 * dpr;
72882
73073
  const renderingContext = {
72883
73074
  ctx,
72884
73075
  dpr,
72885
73076
  thinLineWidth,
72886
73077
  };
72887
- const { width, height } = canvasSize();
73078
+ let { width, height } = canvasSize();
73079
+ width = zoom * width;
73080
+ height = zoom * height;
72888
73081
  canvas.style.width = `${width}px`;
72889
73082
  canvas.style.height = `${height}px`;
72890
73083
  canvas.width = width * dpr;
72891
73084
  canvas.height = height * dpr;
72892
- canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
73085
+ canvas.setAttribute("style", `width:${width}px;height:${height}px;zoom:${1 / zoom}`);
72893
73086
  if (width === 0 || height === 0) {
72894
73087
  return;
72895
73088
  }
@@ -72900,7 +73093,7 @@ function useGridDrawing(refName, model, canvasSize) {
72900
73093
  // you need to shift the coordinates by 0.5 perpendicular to the line's direction.
72901
73094
  // http://diveintohtml5.info/canvas.html#pixel-madness
72902
73095
  ctx.translate(-CANVAS_SHIFT, -CANVAS_SHIFT);
72903
- ctx.scale(dpr, dpr);
73096
+ ctx.scale(dpr * zoom, dpr * zoom);
72904
73097
  rendererStore.draw(renderingContext);
72905
73098
  }
72906
73099
  }
@@ -73136,6 +73329,7 @@ class Highlight extends Component {
73136
73329
  }
73137
73330
  onResizeHighlight(ev, dirX, dirY) {
73138
73331
  const activeSheetId = this.env.model.getters.getActiveSheetId();
73332
+ const zoomedMouseEvent = withZoom(this.env, ev);
73139
73333
  this.highlightState.shiftingMode = "isResizing";
73140
73334
  const z = this.props.range.zone;
73141
73335
  const pivotCol = dirX === 1 ? z.left : z.right;
@@ -73174,11 +73368,12 @@ class Highlight extends Component {
73174
73368
  const mouseUp = () => {
73175
73369
  this.highlightState.shiftingMode = "none";
73176
73370
  };
73177
- this.dragNDropGrid.start(ev, mouseMove, mouseUp, scrollDirection);
73371
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMove, mouseUp, scrollDirection);
73178
73372
  }
73179
73373
  onMoveHighlight(ev) {
73180
73374
  this.highlightState.shiftingMode = "isMoving";
73181
73375
  const z = this.props.range.zone;
73376
+ const zoomedMouseEvent = withZoom(this.env, ev);
73182
73377
  const position = gridOverlayPosition();
73183
73378
  const activeSheetId = this.env.model.getters.getActiveSheetId();
73184
73379
  const initCol = this.env.model.getters.getColIndex(ev.clientX - position.left);
@@ -73215,7 +73410,7 @@ class Highlight extends Component {
73215
73410
  const mouseUp = () => {
73216
73411
  this.highlightState.shiftingMode = "none";
73217
73412
  };
73218
- this.dragNDropGrid.start(ev, mouseMove, mouseUp);
73413
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMove, mouseUp);
73219
73414
  }
73220
73415
  }
73221
73416
 
@@ -73321,11 +73516,12 @@ class HorizontalScrollBar extends Component {
73321
73516
  }
73322
73517
  get position() {
73323
73518
  const { x } = this.env.model.getters.getMainViewportRect();
73519
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
73324
73520
  return {
73325
73521
  left: `${this.props.leftOffset + x}px`,
73326
73522
  bottom: "0px",
73327
- height: `${SCROLLBAR_WIDTH}px`,
73328
- right: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
73523
+ height: `${scrollbarWidth}px`,
73524
+ right: isBrowserFirefox() ? `${scrollbarWidth}px` : "0",
73329
73525
  };
73330
73526
  }
73331
73527
  onScroll(offset) {
@@ -73366,11 +73562,12 @@ class VerticalScrollBar extends Component {
73366
73562
  }
73367
73563
  get position() {
73368
73564
  const { y } = this.env.model.getters.getMainViewportRect();
73565
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
73369
73566
  return {
73370
73567
  top: `${this.props.topOffset + y}px`,
73371
73568
  right: "0px",
73372
- width: `${SCROLLBAR_WIDTH}px`,
73373
- bottom: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
73569
+ width: `${scrollbarWidth}px`,
73570
+ bottom: isBrowserFirefox() ? `${scrollbarWidth}px` : "0",
73374
73571
  };
73375
73572
  }
73376
73573
  onScroll(offset) {
@@ -73579,34 +73776,38 @@ class ColorPickerWidget extends Component {
73579
73776
  }
73580
73777
  }
73581
73778
 
73582
- class FontSizeEditor extends Component {
73583
- static template = "o-spreadsheet-FontSizeEditor";
73779
+ class NumberEditor extends Component {
73780
+ static template = "o-spreadsheet-NumberEditor";
73584
73781
  static props = {
73585
- currentFontSize: Number,
73586
- onFontSizeChanged: Function,
73782
+ currentValue: Number,
73783
+ onValueChange: Function,
73587
73784
  onToggle: { type: Function, optional: true },
73588
73785
  onFocusInput: { type: Function, optional: true },
73589
73786
  class: String,
73787
+ valueIcon: { type: String, optional: true },
73788
+ min: Number,
73789
+ max: Number,
73790
+ title: String,
73791
+ valueList: (Array),
73590
73792
  };
73591
73793
  static defaultProps = {
73592
73794
  onFocusInput: () => { },
73593
73795
  };
73594
73796
  static components = { Popover };
73595
- fontSizes = FONT_SIZES;
73596
73797
  dropdown = useState({ isOpen: false });
73597
- inputRef = useRef("inputFontSize");
73598
- rootEditorRef = useRef("FontSizeEditor");
73599
- fontSizeListRef = useRef("fontSizeList");
73798
+ inputRef = useRef("inputNumber");
73799
+ rootEditorRef = useRef("NumberEditor");
73800
+ valueListRef = useRef("numberList");
73600
73801
  setup() {
73601
73802
  useExternalListener(window, "click", this.onExternalClick, { capture: true });
73602
73803
  onWillUpdateProps((nextProps) => {
73603
73804
  if (this.inputRef.el && document.activeElement !== this.inputRef.el) {
73604
- this.inputRef.el.value = nextProps.currentFontSize;
73805
+ this.inputRef.el.value = nextProps.currentValue;
73605
73806
  }
73606
73807
  });
73607
73808
  onMounted(() => {
73608
73809
  if (this.inputRef.el) {
73609
- this.inputRef.el.value = this.props.currentFontSize.toString();
73810
+ this.inputRef.el.value = this.props.currentValue.toString();
73610
73811
  }
73611
73812
  });
73612
73813
  }
@@ -73619,33 +73820,36 @@ class FontSizeEditor extends Component {
73619
73820
  };
73620
73821
  }
73621
73822
  onExternalClick(ev) {
73622
- if (!isChildEvent(this.fontSizeListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
73623
- this.closeFontList();
73823
+ if (!isChildEvent(this.valueListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
73824
+ this.closeList();
73624
73825
  }
73625
73826
  }
73626
- toggleFontList() {
73827
+ toggleList() {
73627
73828
  const isOpen = this.dropdown.isOpen;
73628
73829
  if (!isOpen) {
73629
73830
  this.props.onToggle?.();
73630
73831
  this.inputRef.el.focus();
73631
73832
  }
73632
73833
  else {
73633
- this.closeFontList();
73834
+ this.closeList();
73634
73835
  }
73635
73836
  }
73636
- closeFontList() {
73837
+ closeList() {
73637
73838
  this.dropdown.isOpen = false;
73638
73839
  }
73639
- setSize(fontSizeStr) {
73640
- const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
73641
- this.props.onFontSizeChanged(fontSize);
73642
- this.closeFontList();
73840
+ setValue(valueStr) {
73841
+ const value = clip(Math.floor(parseFloat(valueStr)), this.props.min, this.props.max);
73842
+ this.props.onValueChange(value);
73843
+ this.closeList();
73643
73844
  }
73644
- setSizeFromInput(ev) {
73645
- this.setSize(ev.target.value);
73845
+ setValueFromInput(ev) {
73846
+ this.setValue(ev.target.value);
73646
73847
  }
73647
- setSizeFromList(fontSizeStr) {
73648
- this.setSize(fontSizeStr);
73848
+ setValueFromList(valueStr) {
73849
+ this.setValue(valueStr);
73850
+ }
73851
+ get currentValue() {
73852
+ return `${this.props.currentValue}`;
73649
73853
  }
73650
73854
  onInputFocused(ev) {
73651
73855
  this.dropdown.isOpen = true;
@@ -73653,17 +73857,33 @@ class FontSizeEditor extends Component {
73653
73857
  }
73654
73858
  onInputKeydown(ev) {
73655
73859
  if (ev.key === "Enter" || ev.key === "Escape") {
73656
- this.closeFontList();
73860
+ this.closeList();
73657
73861
  const target = ev.target;
73658
73862
  // In the case of a ESCAPE key, we get the previous font size back
73659
73863
  if (ev.key === "Escape") {
73660
- target.value = `${this.props.currentFontSize}`;
73864
+ target.value = `${this.props.currentValue}`;
73661
73865
  }
73662
73866
  this.props.onToggle?.();
73663
73867
  }
73664
73868
  }
73665
73869
  }
73666
73870
 
73871
+ class FontSizeEditor extends Component {
73872
+ static template = "o-spreadsheet-FontSizeEditor";
73873
+ static components = { NumberEditor };
73874
+ static props = {
73875
+ currentFontSize: Number,
73876
+ onFontSizeChanged: Function,
73877
+ onToggle: { type: Function, optional: true },
73878
+ onFocusInput: { type: Function, optional: true },
73879
+ class: String,
73880
+ };
73881
+ static defaultProps = {
73882
+ onFocusInput: () => { },
73883
+ };
73884
+ fontSizes = FONT_SIZES;
73885
+ }
73886
+
73667
73887
  class TextStyler extends Component {
73668
73888
  static template = "o-spreadsheet.TextStyler";
73669
73889
  static components = { ColorPickerWidget, ActionButton, FontSizeEditor };
@@ -76680,15 +76900,19 @@ class ConditionalFormattingEditor extends Component {
76680
76900
  this.updateConditionalFormat({ rule: this.state.rules.colorScale });
76681
76901
  this.closeMenus();
76682
76902
  }
76683
- getPreviewGradient() {
76903
+ getColorScalePreviewStyle() {
76684
76904
  const rule = this.state.rules.colorScale;
76685
76905
  const minColor = colorNumberToHex(rule.minimum.color);
76686
76906
  const midColor = colorNumberToHex(rule.midpoint?.color || DEFAULT_COLOR_SCALE_MIDPOINT_COLOR);
76687
76907
  const maxColor = colorNumberToHex(rule.maximum.color);
76688
- const baseString = "background-image: linear-gradient(to right, ";
76689
- return rule.midpoint === undefined
76908
+ const baseString = "linear-gradient(to right, ";
76909
+ const backgroundImage = rule.midpoint === undefined
76690
76910
  ? baseString + minColor + ", " + maxColor + ")"
76691
76911
  : baseString + minColor + ", " + midColor + ", " + maxColor + ")";
76912
+ return cssPropertiesToCss({
76913
+ "background-image": backgroundImage,
76914
+ color: "#000",
76915
+ });
76692
76916
  }
76693
76917
  getThresholdColor(threshold) {
76694
76918
  return threshold
@@ -79034,11 +79258,15 @@ pivotSidePanelRegistry.add("SPREADSHEET", {
79034
79258
  class PivotDesignPanel extends Component {
79035
79259
  static template = "o-spreadsheet-PivotDesignPanel";
79036
79260
  static props = { pivotId: String };
79037
- static components = { Section, Checkbox };
79261
+ static components = { Section, Checkbox, NumberInput };
79038
79262
  store;
79039
79263
  setup() {
79040
79264
  this.store = useLocalStore(PivotSidePanelStore, this.props.pivotId, "neverDefer");
79041
79265
  }
79266
+ updatePivotStyleNumberProperty(valueStr, key) {
79267
+ const value = parseInt(valueStr);
79268
+ this.store.update({ style: { ...this.pivotStyle, [key]: isNaN(value) ? undefined : value } });
79269
+ }
79042
79270
  updatePivotStyleProperty(key, value) {
79043
79271
  this.store.update({ style: { ...this.pivotStyle, [key]: value } });
79044
79272
  }
@@ -80203,6 +80431,7 @@ class TableResizer extends Component {
80203
80431
  const tableZone = this.props.table.range.zone;
80204
80432
  const topLeft = { col: tableZone.left, row: tableZone.top };
80205
80433
  document.body.style.cursor = "nwse-resize";
80434
+ const zoomedMouseEvent = withZoom(this.env, ev);
80206
80435
  const onMouseUp = () => {
80207
80436
  document.body.style.cursor = "";
80208
80437
  const newTableZone = this.state.highlightZone;
@@ -80224,7 +80453,7 @@ class TableResizer extends Component {
80224
80453
  bottom: Math.max(row, topLeft.row),
80225
80454
  };
80226
80455
  };
80227
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
80456
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
80228
80457
  }
80229
80458
  get highlights() {
80230
80459
  if (!this.state.highlightZone)
@@ -80299,7 +80528,9 @@ class Grid extends Component {
80299
80528
  this.paintFormatStore = useStore(PaintFormatStore);
80300
80529
  this.clientFocusStore = useStore(ClientFocusStore);
80301
80530
  useStore(ArrayFormulaHighlight);
80302
- useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
80531
+ useChildSubEnv({
80532
+ getPopoverContainerRect: () => getZoomedRect(this.env.model.getters.getViewportZoomLevel(), this.getGridRect()),
80533
+ });
80303
80534
  useExternalListener(document.body, "cut", this.copy.bind(this, true));
80304
80535
  useExternalListener(document.body, "copy", this.copy.bind(this, false));
80305
80536
  useExternalListener(document.body, "paste", this.paste);
@@ -80325,11 +80556,12 @@ class Grid extends Component {
80325
80556
  return this.highlightStore.highlights;
80326
80557
  }
80327
80558
  get gridOverlayDimensions() {
80559
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
80328
80560
  return cssPropertiesToCss({
80329
80561
  top: `${HEADER_HEIGHT}px`,
80330
80562
  left: `${HEADER_WIDTH}px`,
80331
- height: `calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px)`,
80332
- width: `calc(100% - ${HEADER_WIDTH + SCROLLBAR_WIDTH}px)`,
80563
+ height: `calc(100% - ${HEADER_HEIGHT + scrollbarWidth}px)`,
80564
+ width: `calc(100% - ${HEADER_WIDTH + scrollbarWidth}px)`,
80333
80565
  });
80334
80566
  }
80335
80567
  onClosePopover() {
@@ -80535,8 +80767,8 @@ class Grid extends Component {
80535
80767
  const zone = this.env.model.getters.getSelectedZone();
80536
80768
  const rect = this.env.model.getters.getVisibleRect(zone);
80537
80769
  return {
80538
- left: rect.x + rect.width - AUTOFILL_EDGE_LENGTH / 2,
80539
- top: rect.y + rect.height - AUTOFILL_EDGE_LENGTH / 2,
80770
+ x: rect.x + rect.width - AUTOFILL_EDGE_LENGTH / 2,
80771
+ y: rect.y + rect.height - AUTOFILL_EDGE_LENGTH / 2,
80540
80772
  };
80541
80773
  }
80542
80774
  get isAutofillVisible() {
@@ -80592,8 +80824,8 @@ class Grid extends Component {
80592
80824
  // ---------------------------------------------------------------------------
80593
80825
  // Zone selection with mouse
80594
80826
  // ---------------------------------------------------------------------------
80595
- onCellClicked(col, row, modifiers, ev) {
80596
- ev.preventDefault();
80827
+ onCellClicked(col, row, modifiers, zoomedMouseEvent) {
80828
+ zoomedMouseEvent.ev.preventDefault();
80597
80829
  if (this.composerFocusStore.activeComposer.editionMode === "editing") {
80598
80830
  this.composerFocusStore.activeComposer.stopEdition();
80599
80831
  }
@@ -80627,7 +80859,7 @@ class Grid extends Component {
80627
80859
  this.paintFormatStore.pasteFormat(this.env.model.getters.getSelectedZones());
80628
80860
  }
80629
80861
  };
80630
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
80862
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
80631
80863
  }
80632
80864
  onCellDoubleClicked(col, row) {
80633
80865
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -81841,7 +82073,7 @@ autoCompleteProviders.add("dataValidation", {
81841
82073
  htmlContent: [
81842
82074
  {
81843
82075
  value: value.label,
81844
- color: color ? chipTextColor(color) : undefined,
82076
+ color: chipTextColor(color || GRAY_200),
81845
82077
  backgroundColor: color || GRAY_200,
81846
82078
  classes: ["badge rounded-pill fs-6 fw-normal w-100 mt-1 text-start"],
81847
82079
  },
@@ -82525,6 +82757,7 @@ topbarMenuRegistry
82525
82757
  .add("file", {
82526
82758
  name: _t$1("File"),
82527
82759
  sequence: 10,
82760
+ isReadonlyAllowed: true,
82528
82761
  })
82529
82762
  .addChild("settings", ["file"], {
82530
82763
  name: _t$1("Settings"),
@@ -82539,6 +82772,7 @@ topbarMenuRegistry
82539
82772
  .add("edit", {
82540
82773
  name: _t$1("Edit"),
82541
82774
  sequence: 20,
82775
+ isReadonlyAllowed: true,
82542
82776
  })
82543
82777
  .addChild("undo", ["edit"], {
82544
82778
  ...undo,
@@ -82623,6 +82857,7 @@ topbarMenuRegistry
82623
82857
  .add("view", {
82624
82858
  name: _t$1("View"),
82625
82859
  sequence: 30,
82860
+ isReadonlyAllowed: true,
82626
82861
  })
82627
82862
  .addChild("unfreeze_panes", ["view"], {
82628
82863
  ...unFreezePane,
@@ -82702,6 +82937,11 @@ topbarMenuRegistry
82702
82937
  .addChild("view_formulas", ["view", "show"], {
82703
82938
  ...viewFormulas,
82704
82939
  sequence: 10,
82940
+ })
82941
+ .addChild("zoom", ["view"], {
82942
+ name: _t$1("Zoom"),
82943
+ sequence: 1,
82944
+ icon: "o-spreadsheet-Icon.ZOOM",
82705
82945
  })
82706
82946
  .addChild("view_irregularity_map", ["view"], {
82707
82947
  ...irregularityMap,
@@ -82714,6 +82954,7 @@ topbarMenuRegistry
82714
82954
  .add("insert", {
82715
82955
  name: _t$1("Insert"),
82716
82956
  sequence: 40,
82957
+ isReadonlyAllowed: true,
82717
82958
  })
82718
82959
  .addChild("insert_row", ["insert"], {
82719
82960
  ...insertRow,
@@ -82825,7 +83066,11 @@ topbarMenuRegistry
82825
83066
  // ---------------------------------------------------------------------
82826
83067
  // FORMAT MENU ITEMS
82827
83068
  // ---------------------------------------------------------------------
82828
- .add("format", { name: _t$1("Format"), sequence: 50 })
83069
+ .add("format", {
83070
+ name: _t$1("Format"),
83071
+ sequence: 50,
83072
+ isReadonlyAllowed: true,
83073
+ })
82829
83074
  .addChild("format_number", ["format"], {
82830
83075
  ...formatNumberMenuItemSpec,
82831
83076
  name: _t$1("Number"),
@@ -82917,6 +83162,7 @@ topbarMenuRegistry
82917
83162
  .add("data", {
82918
83163
  name: _t$1("Data"),
82919
83164
  sequence: 60,
83165
+ isReadonlyAllowed: true,
82920
83166
  })
82921
83167
  .addChild("sort_range", ["data"], {
82922
83168
  ...sortRange,
@@ -82990,6 +83236,10 @@ topbarMenuRegistry
82990
83236
  })
82991
83237
  .addChild("reinsert_dynamic_pivot", ["data"], reinsertDynamicPivotMenu)
82992
83238
  .addChild("reinsert_static_pivot", ["data"], reinsertStaticPivotMenu);
83239
+ // Zoom
83240
+ ZOOM_VALUES.forEach((zoom) => {
83241
+ topbarMenuRegistry.addChild(`zoom${zoom}`, ["view", "zoom"], zoomAction(zoom));
83242
+ });
82993
83243
 
82994
83244
  const genericRepeatsTransforms = [
82995
83245
  repeatSheetDependantCommand,
@@ -84020,7 +84270,9 @@ class SpreadsheetDashboard extends Component {
84020
84270
  this.gridRef = useRef("grid");
84021
84271
  this.hoveredCell = useStore(DelayedHoveredCellStore);
84022
84272
  this.clickableCellsStore = useStore(ClickableCellsStore);
84023
- useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
84273
+ useChildSubEnv({
84274
+ getPopoverContainerRect: () => getZoomedRect(this.env.model.getters.getViewportZoomLevel(), this.getGridRect()),
84275
+ });
84024
84276
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimension());
84025
84277
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
84026
84278
  this.moveCanvas(deltaX, deltaY);
@@ -85086,6 +85338,35 @@ class NumberFormatsTool extends Component {
85086
85338
  }
85087
85339
  }
85088
85340
 
85341
+ class ToolBarZoom extends Component {
85342
+ static template = "o-spreadsheet-TopBarZoom";
85343
+ static components = { NumberEditor };
85344
+ static props = { class: String };
85345
+ topBarToolStore;
85346
+ valueList = ZOOM_VALUES;
85347
+ setup() {
85348
+ this.topBarToolStore = useToolBarDropdownStore();
85349
+ }
85350
+ get currentFontSize() {
85351
+ const zoom = this.env.model.getters.getViewportZoomLevel() || 1;
85352
+ return zoom * 100;
85353
+ }
85354
+ setZoom(fontSize) {
85355
+ this.env.model.dispatch("SET_ZOOM", { zoom: fontSize / 100 });
85356
+ }
85357
+ toggle() {
85358
+ if (this.topBarToolStore.isActive) {
85359
+ this.topBarToolStore.closeDropdowns();
85360
+ }
85361
+ else {
85362
+ this.topBarToolStore.openDropdown();
85363
+ }
85364
+ }
85365
+ onFocusInput() {
85366
+ this.topBarToolStore.openDropdown();
85367
+ }
85368
+ }
85369
+
85089
85370
  const topBarToolBarRegistry = new ToolBarRegistry();
85090
85371
  topBarToolBarRegistry
85091
85372
  .add("edit")
@@ -85119,6 +85400,13 @@ topBarToolBarRegistry
85119
85400
  class: "o-hoverable-button o-toolbar-button",
85120
85401
  },
85121
85402
  sequence: 4,
85403
+ })
85404
+ .addChild("edit", {
85405
+ component: ToolBarZoom,
85406
+ props: {
85407
+ class: "o-menu-item-button o-hoverable-button o-toolbar-button",
85408
+ },
85409
+ sequence: 5,
85122
85410
  })
85123
85411
  .add("numberFormat")
85124
85412
  .addChild("numberFormat", {
@@ -85562,6 +85850,7 @@ class Spreadsheet extends Component {
85562
85850
  notifyUser: { type: Function, optional: true },
85563
85851
  raiseError: { type: Function, optional: true },
85564
85852
  askConfirmation: { type: Function, optional: true },
85853
+ colorScheme: { type: String, optional: true },
85565
85854
  };
85566
85855
  static components = {
85567
85856
  TopBar,
@@ -85585,6 +85874,7 @@ class Spreadsheet extends Component {
85585
85874
  }
85586
85875
  getStyle() {
85587
85876
  const properties = {};
85877
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
85588
85878
  if (this.env.isDashboard()) {
85589
85879
  properties["grid-template-rows"] = `auto`;
85590
85880
  }
@@ -85595,6 +85885,8 @@ class Spreadsheet extends Component {
85595
85885
  ? `${this.sidePanel.totalPanelSize || DEFAULT_SIDE_PANEL_SIZE}px`
85596
85886
  : "auto";
85597
85887
  properties["grid-template-columns"] = `auto ${columnWidth}`;
85888
+ properties["--os-scrollbar-width"] = `${scrollbarWidth}px`;
85889
+ properties["color-scheme"] = this.props.colorScheme;
85598
85890
  return cssPropertiesToCss(properties);
85599
85891
  }
85600
85892
  setup() {
@@ -85723,9 +86015,11 @@ class Spreadsheet extends Component {
85723
86015
  get gridContainerStyle() {
85724
86016
  const gridColSize = GROUP_LAYER_WIDTH * this.rowLayers.length;
85725
86017
  const gridRowSize = GROUP_LAYER_WIDTH * this.colLayers.length;
86018
+ const zoom = this.env.model.getters.getViewportZoomLevel();
85726
86019
  return cssPropertiesToCss({
85727
86020
  "grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`, // +2: margins
85728
86021
  "grid-template-rows": `${gridRowSize ? gridRowSize + 2 : 0}px auto`,
86022
+ zoom: `${zoom}`,
85729
86023
  });
85730
86024
  }
85731
86025
  get rowLayers() {
@@ -85737,6 +86031,8 @@ class Spreadsheet extends Component {
85737
86031
  return this.env.model.getters.getVisibleGroupLayers(sheetId, "COL");
85738
86032
  }
85739
86033
  getGridSize() {
86034
+ const zoom = this.env.model.getters.getViewportZoomLevel();
86035
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
85740
86036
  const topBarHeight = this.spreadsheetRef.el
85741
86037
  ?.querySelector(".o-spreadsheet-topbar-wrapper")
85742
86038
  ?.getBoundingClientRect().height || 0;
@@ -85750,10 +86046,16 @@ class Spreadsheet extends Component {
85750
86046
  topBarHeight -
85751
86047
  bottomBarHeight;
85752
86048
  return {
85753
- width: Math.max(gridWidth - SCROLLBAR_WIDTH, 0),
85754
- height: Math.max(gridHeight - SCROLLBAR_WIDTH, 0),
86049
+ width: Math.max(gridWidth / zoom - scrollbarWidth, 0),
86050
+ height: Math.max(gridHeight / zoom - scrollbarWidth, 0),
85755
86051
  };
85756
86052
  }
86053
+ getSpreadSheetClasses() {
86054
+ return [
86055
+ this.env.isSmall ? "o-spreadsheet-mobile" : "",
86056
+ this.props.colorScheme === "dark" ? "dark" : "",
86057
+ ].join(" ");
86058
+ }
85757
86059
  }
85758
86060
 
85759
86061
  class ComboChart extends AbstractChart {
@@ -88201,6 +88503,7 @@ const components = {
88201
88503
  ChartDashboardMenu,
88202
88504
  FullScreenFigure,
88203
88505
  NumberInput,
88506
+ TopBar,
88204
88507
  };
88205
88508
  const hooks = {
88206
88509
  useDragAndDropListItems,
@@ -88250,6 +88553,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
88250
88553
  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
88554
 
88252
88555
 
88253
- __info__.version = "19.1.0-alpha.10";
88254
- __info__.date = "2025-10-30T12:26:30.196Z";
88255
- __info__.hash = "d0b65e9";
88556
+ __info__.version = "19.1.0-alpha.12";
88557
+ __info__.date = "2025-11-12T14:17:07.713Z";
88558
+ __info__.hash = "6fefc9c";