@odoo/o-spreadsheet 17.2.1 → 17.3.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.1
7
- * @date 2024-03-25T09:41:58.737Z
8
- * @hash f97284c
6
+ * @version 17.3.0-alpha.1
7
+ * @date 2024-03-25T09:43:36.072Z
8
+ * @hash 4095c41
9
9
  */
10
10
 
11
11
  'use strict';
@@ -4203,6 +4203,10 @@ function organizeZone(zone) {
4203
4203
  function positionToZone(position) {
4204
4204
  return { left: position.col, right: position.col, top: position.row, bottom: position.row };
4205
4205
  }
4206
+ /** Transform a zone into a zone with only its top-left position */
4207
+ function zoneToTopLeft(zone) {
4208
+ return { ...zone, right: zone.left, bottom: zone.top };
4209
+ }
4206
4210
  function isFullRow(zone) {
4207
4211
  return zone.right === undefined;
4208
4212
  }
@@ -4242,6 +4246,16 @@ function getZonesRows(zones) {
4242
4246
  }
4243
4247
  return set;
4244
4248
  }
4249
+ function unionPositionsToZone(positions) {
4250
+ const zone = { top: Infinity, left: Infinity, bottom: -Infinity, right: -Infinity };
4251
+ for (const { col, row } of positions) {
4252
+ zone.top = Math.min(zone.top, row);
4253
+ zone.left = Math.min(zone.left, col);
4254
+ zone.bottom = Math.max(zone.bottom, row);
4255
+ zone.right = Math.max(zone.right, col);
4256
+ }
4257
+ return zone;
4258
+ }
4245
4259
 
4246
4260
  class RangeImpl {
4247
4261
  getSheetSize;
@@ -5571,7 +5585,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
5571
5585
  const spreader = this.getters.getArrayFormulaSpreadingOn(position);
5572
5586
  let cell = this.getters.getCell(position);
5573
5587
  const evaluatedCell = this.getters.getEvaluatedCell(position);
5574
- if (spreader) {
5588
+ if (spreader && !deepEquals(spreader, position)) {
5575
5589
  const isSpreaderCopied = rowsIndexes.includes(spreader.row) && columnsIndexes.includes(spreader.col);
5576
5590
  const content = isSpreaderCopied
5577
5591
  ? ""
@@ -6218,19 +6232,25 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6218
6232
  tableCellsInRow.push({});
6219
6233
  continue;
6220
6234
  }
6235
+ const coreTable = this.getters.getCoreTable(position);
6236
+ const tableZone = coreTable?.range.zone;
6221
6237
  // Copy whole table
6222
- if (zones.some((z) => isZoneInside(table.range.zone, z))) {
6223
- copiedTablesIds.add(table.id);
6238
+ if (coreTable && tableZone && zones.some((z) => isZoneInside(tableZone, z))) {
6239
+ copiedTablesIds.add(coreTable.id);
6224
6240
  const values = [];
6225
- for (const col of range(table.range.zone.left, table.range.zone.right + 1)) {
6226
- values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: table.range.zone.top }));
6241
+ for (const col of range(tableZone.left, tableZone.right + 1)) {
6242
+ values.push(this.getters.getFilterHiddenValues({ sheetId, col, row: tableZone.top }));
6227
6243
  }
6228
6244
  tableCellsInRow.push({
6229
- table: { filtersValues: values, range: table.range, config: table.config },
6245
+ table: {
6246
+ range: coreTable.range,
6247
+ config: coreTable.config,
6248
+ type: coreTable.type,
6249
+ },
6230
6250
  });
6231
6251
  }
6232
6252
  // Copy only style of cell
6233
- else {
6253
+ else if (table) {
6234
6254
  tableCellsInRow.push({ style: this.getTableStyleToCopy(position) });
6235
6255
  }
6236
6256
  }
@@ -6301,7 +6321,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6301
6321
  }
6302
6322
  pasteTableCell(sheetId, tableCell, position, options) {
6303
6323
  if (tableCell.table && !options?.pasteOption) {
6304
- const { range: tableRange, filtersValues } = tableCell.table;
6324
+ const { range: tableRange } = tableCell.table;
6305
6325
  const zoneDims = zoneToDimension(tableRange.zone);
6306
6326
  const newTableZone = {
6307
6327
  left: position.col,
@@ -6313,18 +6333,13 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6313
6333
  sheetId: position.sheetId,
6314
6334
  ranges: [this.getters.getRangeDataFromZone(sheetId, newTableZone)],
6315
6335
  config: tableCell.table.config,
6336
+ tableType: tableCell.table.type,
6316
6337
  });
6317
- for (const i of range(0, filtersValues.length)) {
6318
- this.dispatch("UPDATE_FILTER", {
6319
- sheetId: position.sheetId,
6320
- col: newTableZone.left + i,
6321
- row: newTableZone.top,
6322
- hiddenValues: filtersValues[i],
6323
- });
6324
- }
6325
6338
  }
6326
6339
  // Do not paste table style if we're inside another table
6327
- if (!this.getters.getTable(position)) {
6340
+ // We cannot check for dynamic tables, because at this point the paste can have changed the evaluation, and the
6341
+ // dynamic tables are not yet computed
6342
+ if (!this.getters.getCoreTable(position)) {
6328
6343
  if (tableCell.style?.style && options?.pasteOption !== "asValue") {
6329
6344
  this.dispatch("UPDATE_CELL", { ...position, style: tableCell.style.style });
6330
6345
  }
@@ -7426,9 +7441,11 @@ const TableTerms = {
7426
7441
  bandedColumns: _t("Banded columns"),
7427
7442
  automaticAutofill: _t("Automatically autofill formulas"),
7428
7443
  totalRow: _t("Total row"),
7444
+ isDynamic: _t("Auto-adjust to formula result"),
7429
7445
  },
7430
7446
  Tooltips: {
7431
7447
  filterWithoutHeader: _t("Cannot have filters without a header row"),
7448
+ isDynamic: _t("For tables based on array formulas only"),
7432
7449
  },
7433
7450
  };
7434
7451
 
@@ -22229,6 +22246,7 @@ class LinkDisplay extends owl.Component {
22229
22246
  }
22230
22247
  edit() {
22231
22248
  const { col, row } = this.props.cellPosition;
22249
+ this.env.model.selection.selectCell(col, row);
22232
22250
  this.cellPopovers.open({ col, row }, "LinkEditor");
22233
22251
  }
22234
22252
  unlink() {
@@ -23345,13 +23363,20 @@ const TABLE_PRESETS = {
23345
23363
  * If a single cell is selected, expand the selection to non-empty adjacent cells to create a table.
23346
23364
  */
23347
23365
  function interactiveCreateTable(env, sheetId, tableConfig) {
23348
- const selection = env.model.getters.getSelectedZones();
23349
- if (selection.length === 1 && getZoneArea(selection[0]) === 1) {
23366
+ let target = env.model.getters.getSelectedZones();
23367
+ let isDynamic = env.model.getters.canCreateDynamicTableOnZones(sheetId, target);
23368
+ if (target.length === 1 && !isDynamic && getZoneArea(target[0]) === 1) {
23350
23369
  env.model.selection.selectTableAroundSelection();
23370
+ target = env.model.getters.getSelectedZones();
23371
+ isDynamic = env.model.getters.canCreateDynamicTableOnZones(sheetId, target);
23351
23372
  }
23352
- const target = env.model.getters.getSelectedZones();
23353
23373
  const ranges = target.map((zone) => env.model.getters.getRangeDataFromZone(sheetId, zone));
23354
- const result = env.model.dispatch("CREATE_TABLE", { ranges, sheetId, config: tableConfig });
23374
+ const result = env.model.dispatch("CREATE_TABLE", {
23375
+ ranges,
23376
+ sheetId,
23377
+ config: tableConfig,
23378
+ tableType: isDynamic ? "dynamic" : "static",
23379
+ });
23355
23380
  if (result.isCancelledBecause("TableOverlap" /* CommandResult.TableOverlap */)) {
23356
23381
  env.raiseError(TableTerms.Errors.TableOverlap);
23357
23382
  }
@@ -23799,9 +23824,13 @@ const INSERT_TABLE = (env) => {
23799
23824
  };
23800
23825
  const DELETE_SELECTED_TABLE = (env) => {
23801
23826
  const position = env.model.getters.getActivePosition();
23827
+ const table = env.model.getters.getTable(position);
23828
+ if (!table) {
23829
+ return;
23830
+ }
23802
23831
  env.model.dispatch("REMOVE_TABLE", {
23803
23832
  sheetId: position.sheetId,
23804
- target: [positionToZone(position)],
23833
+ target: [table.range.zone],
23805
23834
  });
23806
23835
  };
23807
23836
  //------------------------------------------------------------------------------
@@ -30309,6 +30338,24 @@ function getTableContentZone(tableZone, tableConfig) {
30309
30338
  const contentZone = { ...tableZone, top: tableZone.top + numberOfHeaders };
30310
30339
  return contentZone.top <= contentZone.bottom ? contentZone : undefined;
30311
30340
  }
30341
+ function getTableTopLeft(table) {
30342
+ const range = table.range;
30343
+ return { row: range.zone.top, col: range.zone.left, sheetId: range.sheetId };
30344
+ }
30345
+ function createFilter(id, range, config, createRange) {
30346
+ const zone = range.zone;
30347
+ if (zone.left !== zone.right) {
30348
+ throw new Error("Can only define a filter on a single column");
30349
+ }
30350
+ const filteredZone = { ...zone, top: zone.top + config.numberOfHeaders };
30351
+ const filteredRange = createRange(range.sheetId, filteredZone);
30352
+ return {
30353
+ id,
30354
+ rangeWithHeaders: range,
30355
+ col: zone.left,
30356
+ filteredRange: filteredZone.top > filteredZone.bottom ? undefined : filteredRange,
30357
+ };
30358
+ }
30312
30359
  function getComputedTableStyle(tableConfig, numberOfCols, numberOfRows) {
30313
30360
  return {
30314
30361
  borders: getAllTableBorders(tableConfig, numberOfCols, numberOfRows),
@@ -30746,6 +30793,11 @@ css /* scss */ `
30746
30793
  color: #ffffff;
30747
30794
  background: #d94b4b;
30748
30795
  }
30796
+
30797
+ .o-info-icon {
30798
+ width: 14px;
30799
+ height: 14px;
30800
+ }
30749
30801
  }
30750
30802
  `;
30751
30803
  class TablePanel extends owl.Component {
@@ -30777,6 +30829,29 @@ class TablePanel extends owl.Component {
30777
30829
  const numberOfHeaders = hasHeaders ? 1 : 0;
30778
30830
  this.updateNumberOfHeaders(numberOfHeaders);
30779
30831
  }
30832
+ updateTableIsDynamic(isDynamic) {
30833
+ const newTableType = isDynamic ? "dynamic" : "forceStatic";
30834
+ if (newTableType === this.props.table.type) {
30835
+ return;
30836
+ }
30837
+ const uiTable = this.env.model.getters.getTable(getTableTopLeft(this.props.table));
30838
+ if (!uiTable) {
30839
+ return;
30840
+ }
30841
+ const sheetId = this.env.model.getters.getActiveSheetId();
30842
+ const result = this.env.model.dispatch("UPDATE_TABLE", {
30843
+ sheetId,
30844
+ zone: this.props.table.range.zone,
30845
+ newTableRange: uiTable.range.rangeData,
30846
+ tableType: newTableType,
30847
+ });
30848
+ const updatedTable = this.env.model.getters.getCoreTable(getTableTopLeft(this.props.table));
30849
+ if (result.isSuccessful && updatedTable) {
30850
+ const newTableRange = updatedTable.range;
30851
+ this.state.tableXc = this.env.model.getters.getRangeString(newTableRange, sheetId);
30852
+ this.state.tableZoneErrors = [];
30853
+ }
30854
+ }
30780
30855
  onChangeNumberOfHeaders(ev) {
30781
30856
  const input = ev.target;
30782
30857
  const numberOfHeaders = parseInt(input.value);
@@ -30800,35 +30875,59 @@ class TablePanel extends owl.Component {
30800
30875
  }
30801
30876
  const sheetId = this.env.model.getters.getActiveSheetId();
30802
30877
  this.state.tableXc = ranges[0];
30878
+ const newTableRange = this.env.model.getters.getRangeFromSheetXC(sheetId, this.state.tableXc);
30803
30879
  this.state.tableZoneErrors = this.env.model.canDispatch("UPDATE_TABLE", {
30804
30880
  sheetId,
30805
30881
  zone: this.props.table.range.zone,
30806
30882
  newTableRange: this.env.model.getters.getRangeDataFromXc(sheetId, this.state.tableXc),
30883
+ tableType: this.getNewTableType(newTableRange.zone),
30807
30884
  }).reasons;
30808
30885
  }
30809
30886
  onRangeConfirmed() {
30810
30887
  const sheetId = this.env.model.getters.getActiveSheetId();
30811
- const newRange = this.env.model.getters.getRangeFromSheetXC(sheetId, this.state.tableXc);
30888
+ let newRange = this.env.model.getters.getRangeFromSheetXC(sheetId, this.state.tableXc);
30889
+ if (getZoneArea(newRange.zone) === 1) {
30890
+ const extendedZone = this.env.model.getters.getContiguousZone(sheetId, newRange.zone);
30891
+ newRange = this.env.model.getters.getRangeFromZone(sheetId, extendedZone);
30892
+ }
30812
30893
  const result = this.env.model.dispatch("UPDATE_TABLE", {
30813
30894
  sheetId,
30814
30895
  zone: this.props.table.range.zone,
30815
30896
  newTableRange: newRange.rangeData,
30897
+ tableType: this.getNewTableType(newRange.zone),
30816
30898
  });
30817
- if (result.isSuccessful) {
30818
- const position = { col: newRange.zone.left, row: newRange.zone.top };
30899
+ const position = { sheetId, col: newRange.zone.left, row: newRange.zone.top };
30900
+ const updatedTable = this.env.model.getters.getCoreTable(position);
30901
+ if (result.isSuccessful && updatedTable) {
30902
+ const newTopLeft = getTableTopLeft(updatedTable);
30819
30903
  this.env.model.selection.selectZone({
30820
- zone: positionToZone(position),
30821
- cell: position,
30904
+ zone: positionToZone(newTopLeft),
30905
+ cell: newTopLeft,
30822
30906
  });
30907
+ const newTableRange = updatedTable.range;
30908
+ this.state.tableXc = this.env.model.getters.getRangeString(newTableRange, sheetId);
30909
+ }
30910
+ else {
30911
+ const oldTableRange = this.props.table.range;
30912
+ this.state.tableXc = this.env.model.getters.getRangeString(oldTableRange, sheetId);
30823
30913
  }
30824
30914
  this.state.tableZoneErrors = [];
30825
- this.state.tableXc = result.isSuccessful
30826
- ? this.state.tableXc
30827
- : this.env.model.getters.getRangeString(this.props.table.range, sheetId);
30828
30915
  }
30829
30916
  deleteTable() {
30830
30917
  const sheetId = this.env.model.getters.getActiveSheetId();
30831
- this.env.model.dispatch("REMOVE_TABLE", { sheetId, target: [this.props.table.range.zone] });
30918
+ this.env.model.dispatch("REMOVE_TABLE", {
30919
+ sheetId,
30920
+ target: [this.props.table.range.zone],
30921
+ });
30922
+ }
30923
+ getNewTableType(newTableZone) {
30924
+ if (this.props.table.type === "forceStatic") {
30925
+ return "forceStatic";
30926
+ }
30927
+ const sheetId = this.env.model.getters.getActiveSheetId();
30928
+ return this.env.model.getters.canCreateDynamicTableOnZones(sheetId, [newTableZone])
30929
+ ? "dynamic"
30930
+ : "static";
30832
30931
  }
30833
30932
  get tableConfig() {
30834
30933
  return this.props.table.config;
@@ -30846,6 +30945,14 @@ class TablePanel extends owl.Component {
30846
30945
  get hasFilterCheckboxTooltip() {
30847
30946
  return this.canHaveFilters ? undefined : TableTerms.Tooltips.filterWithoutHeader;
30848
30947
  }
30948
+ get canBeDynamic() {
30949
+ const sheetId = this.env.model.getters.getActiveSheetId();
30950
+ return (this.props.table.type === "dynamic" ||
30951
+ this.env.model.getters.canCreateDynamicTableOnZones(sheetId, [this.props.table.range.zone]));
30952
+ }
30953
+ get dynamicTableTooltip() {
30954
+ return TableTerms.Tooltips.isDynamic;
30955
+ }
30849
30956
  }
30850
30957
 
30851
30958
  const sidePanelRegistry = new Registry();
@@ -30908,11 +31015,8 @@ sidePanelRegistry.add("TableSidePanel", {
30908
31015
  if (!table) {
30909
31016
  return { isOpen: false };
30910
31017
  }
30911
- return {
30912
- isOpen: true,
30913
- props: { table },
30914
- key: table.id,
30915
- };
31018
+ const coreTable = getters.getCoreTable(getTableTopLeft(table));
31019
+ return { isOpen: true, props: { table: coreTable }, key: table.id };
30916
31020
  },
30917
31021
  });
30918
31022
 
@@ -31857,9 +31961,6 @@ class FunctionDescriptionProvider extends owl.Component {
31857
31961
  this.assistantState.allowCellSelectionBehind = false;
31858
31962
  }, 2000);
31859
31963
  }
31860
- get formulaArgSeparator() {
31861
- return this.env.model.getters.getLocale().formulaArgSeparator + " ";
31862
- }
31863
31964
  }
31864
31965
 
31865
31966
  const functions$2 = functionRegistry.content;
@@ -32757,8 +32858,7 @@ class FilterIconsOverlay extends owl.Component {
32757
32858
  };
32758
32859
  getFilterHeadersPositions() {
32759
32860
  const sheetId = this.env.model.getters.getActiveSheetId();
32760
- const headerPositions = this.env.model.getters.getFilterHeaders(sheetId);
32761
- return headerPositions.map((position) => ({ sheetId, ...position }));
32861
+ return this.env.model.getters.getFilterHeaders(sheetId);
32762
32862
  }
32763
32863
  }
32764
32864
 
@@ -44827,22 +44927,12 @@ class SheetPlugin extends CorePlugin {
44827
44927
  }
44828
44928
 
44829
44929
  class TablePlugin extends CorePlugin {
44830
- static getters = [
44831
- "getFilter",
44832
- "getFilters",
44833
- "getTable",
44834
- "getTables",
44835
- "getTablesInZone",
44836
- "getTablesOverlappingZones",
44837
- "getFilterId",
44838
- "getFilterHeaders",
44839
- "isFilterHeader",
44840
- ];
44930
+ static getters = ["getCoreTable", "getCoreTables"];
44841
44931
  tables = {};
44842
44932
  adaptRanges(applyChange, sheetId) {
44843
44933
  const sheetIds = sheetId ? [sheetId] : this.getters.getSheetIds();
44844
44934
  for (const sheetId of sheetIds) {
44845
- for (const table of this.getTables(sheetId)) {
44935
+ for (const table of this.getCoreTables(sheetId)) {
44846
44936
  this.applyRangeChangeOnTable(sheetId, table, applyChange);
44847
44937
  }
44848
44938
  }
@@ -44858,15 +44948,16 @@ class TablePlugin extends CorePlugin {
44858
44948
  ? "TableOverlap" /* CommandResult.TableOverlap */
44859
44949
  : "Success" /* CommandResult.Success */, (cmd) => this.checkTableConfigUpdateIsValid(cmd.config));
44860
44950
  case "UPDATE_TABLE":
44861
- const updatedTable = this.getTables(cmd.sheetId).find((table) => deepEquals(table.range.zone, cmd.zone));
44951
+ const updatedTable = this.getTableFromZone(cmd.sheetId, cmd.zone);
44862
44952
  if (!updatedTable) {
44863
44953
  return "TableNotFound" /* CommandResult.TableNotFound */;
44864
44954
  }
44865
44955
  return this.checkValidations(cmd, this.checkUpdatedTableZoneIsValid, (cmd) => this.checkTableConfigUpdateIsValid(cmd.config));
44866
44956
  case "ADD_MERGE":
44867
- for (const merge of cmd.target) {
44868
- for (const table of this.getTables(cmd.sheetId)) {
44869
- if (overlap(table.range.zone, merge)) {
44957
+ for (const table of this.getCoreTables(cmd.sheetId)) {
44958
+ const tableZone = table.range.zone;
44959
+ for (const merge of cmd.target) {
44960
+ if (overlap(tableZone, merge)) {
44870
44961
  return "MergeInTable" /* CommandResult.MergeInTable */;
44871
44962
  }
44872
44963
  }
@@ -44888,8 +44979,11 @@ class TablePlugin extends CorePlugin {
44888
44979
  }
44889
44980
  case "DUPLICATE_SHEET": {
44890
44981
  const newTables = {};
44891
- for (const table of this.getTables(cmd.sheetId)) {
44892
- newTables[table.id] = this.copyTableForSheet(cmd.sheetIdTo, table);
44982
+ for (const table of this.getCoreTables(cmd.sheetId)) {
44983
+ newTables[table.id] =
44984
+ table.type === "dynamic"
44985
+ ? this.copyDynamicTableForSheet(cmd.sheetIdTo, table)
44986
+ : this.copyStaticTableForSheet(cmd.sheetIdTo, table);
44893
44987
  }
44894
44988
  this.history.update("tables", cmd.sheetIdTo, newTables);
44895
44989
  break;
@@ -44900,14 +44994,17 @@ class TablePlugin extends CorePlugin {
44900
44994
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
44901
44995
  this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
44902
44996
  const id = this.uuidGenerator.uuidv4();
44903
- const newTable = this.createTable(id, union, cmd.config || DEFAULT_TABLE_CONFIG);
44997
+ const config = cmd.config || DEFAULT_TABLE_CONFIG;
44998
+ const newTable = cmd.tableType === "dynamic"
44999
+ ? this.createDynamicTable(id, union, config)
45000
+ : this.createStaticTable(id, cmd.tableType, union, config);
44904
45001
  this.history.update("tables", cmd.sheetId, newTable.id, newTable);
44905
45002
  break;
44906
45003
  }
44907
45004
  case "REMOVE_TABLE": {
44908
45005
  const tables = {};
44909
- for (const table of this.getTables(cmd.sheetId)) {
44910
- if (cmd.target.every((zone) => !intersection(zone, table.range.zone))) {
45006
+ for (const table of this.getCoreTables(cmd.sheetId)) {
45007
+ if (cmd.target.every((zone) => !intersection(table.range.zone, zone))) {
44911
45008
  tables[table.id] = table;
44912
45009
  }
44913
45010
  }
@@ -44915,23 +45012,15 @@ class TablePlugin extends CorePlugin {
44915
45012
  break;
44916
45013
  }
44917
45014
  case "UPDATE_TABLE": {
44918
- const table = this.getTables(cmd.sheetId).find((table) => deepEquals(table.range.zone, cmd.zone));
44919
- if (table) {
44920
- const newTableRange = cmd.newTableRange
44921
- ? this.getters.getRangeFromRangeData(cmd.newTableRange)
44922
- : undefined;
44923
- if (newTableRange) {
44924
- const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, newTableRange.zone);
44925
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
44926
- }
44927
- const newTable = this.updateTable(table, newTableRange, cmd.config);
44928
- this.history.update("tables", cmd.sheetId, table.id, newTable);
44929
- }
45015
+ this.updateTable(cmd);
44930
45016
  break;
44931
45017
  }
44932
45018
  case "UPDATE_CELL": {
44933
45019
  const sheetId = cmd.sheetId;
44934
- for (const table of this.getTables(sheetId)) {
45020
+ for (const table of this.getCoreTables(sheetId)) {
45021
+ if (table.type === "dynamic") {
45022
+ continue;
45023
+ }
44935
45024
  const direction = this.canUpdateCellCmdExtendTable(cmd, table);
44936
45025
  if (direction === "down") {
44937
45026
  this.extendTableDown(sheetId, table);
@@ -44955,62 +45044,24 @@ class TablePlugin extends CorePlugin {
44955
45044
  }
44956
45045
  }
44957
45046
  }
44958
- getFilters(sheetId) {
44959
- return this.getTables(sheetId)
44960
- .filter((table) => table.config.hasFilters)
44961
- .map((table) => table.filters)
44962
- .flat();
44963
- }
44964
- getTables(sheetId) {
45047
+ getCoreTables(sheetId) {
44965
45048
  return this.tables[sheetId] ? Object.values(this.tables[sheetId]).filter(isDefined$1) : [];
44966
45049
  }
44967
- getFilter(position) {
44968
- const table = this.getTable(position);
44969
- if (!table || !table.config.hasFilters) {
44970
- return undefined;
44971
- }
44972
- return table.filters.find((filter) => filter.col === position.col);
44973
- }
44974
- getFilterId(position) {
44975
- return this.getFilter(position)?.id;
44976
- }
44977
- getTable({ sheetId, col, row }) {
44978
- return this.getTables(sheetId).find((table) => isInside(col, row, table.range.zone));
44979
- }
44980
- /** Get the filter tables that are fully inside the given zone */
44981
- getTablesInZone(sheetId, zone) {
44982
- return this.getTables(sheetId).filter((table) => isZoneInside(table.range.zone, zone));
45050
+ getCoreTable({ sheetId, col, row }) {
45051
+ return this.getCoreTables(sheetId).find((table) => isInside(col, row, table.range.zone));
44983
45052
  }
44984
45053
  getTablesOverlappingZones(sheetId, zones) {
44985
- return this.getTables(sheetId).filter((table) => zones.some((zone) => overlap(table.range.zone, zone)));
44986
- }
44987
- getFilterHeaders(sheetId) {
44988
- const headers = [];
44989
- for (const table of this.getTables(sheetId)) {
44990
- if (!table.config.hasFilters) {
44991
- continue;
44992
- }
44993
- const zone = table.range.zone;
44994
- const row = zone.top;
44995
- for (let col = zone.left; col <= zone.right; col++) {
44996
- headers.push({ col, row });
44997
- }
44998
- }
44999
- return headers;
45000
- }
45001
- isFilterHeader({ sheetId, col, row }) {
45002
- const headers = this.getFilterHeaders(sheetId);
45003
- return headers.some((header) => header.col === col && header.row === row);
45054
+ return this.getCoreTables(sheetId).filter((table) => zones.some((zone) => overlap(table.range.zone, zone)));
45004
45055
  }
45005
45056
  /** Extend a table down one row */
45006
45057
  extendTableDown(sheetId, table) {
45007
45058
  const newRange = this.getters.extendRange(table.range, "ROW", 1);
45008
- this.history.update("tables", sheetId, table.id, this.updateTable(table, newRange));
45059
+ this.history.update("tables", sheetId, table.id, this.updateStaticTable(table, newRange));
45009
45060
  }
45010
45061
  /** Extend a table right one col */
45011
45062
  extendTableRight(sheetId, table) {
45012
45063
  const newRange = this.getters.extendRange(table.range, "COL", 1);
45013
- this.history.update("tables", sheetId, table.id, this.updateTable(table, newRange));
45064
+ this.history.update("tables", sheetId, table.id, this.updateStaticTable(table, newRange));
45014
45065
  }
45015
45066
  /**
45016
45067
  * Check if an UpdateCell command should cause the given table to be extended by one row or col.
@@ -45047,12 +45098,22 @@ class TablePlugin extends CorePlugin {
45047
45098
  const cellContent = this.getters.getCell(cellPosition)?.content;
45048
45099
  if (cellContent ||
45049
45100
  this.getters.isInMerge(cellPosition) ||
45050
- this.getters.getTable(cellPosition)) {
45101
+ this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
45051
45102
  return "none";
45052
45103
  }
45053
45104
  }
45054
45105
  return direction;
45055
45106
  }
45107
+ getTableFromZone(sheetId, zone) {
45108
+ for (const table of this.getCoreTables(sheetId)) {
45109
+ const tableZone = table.range.zone;
45110
+ // Only check top left to match dynamic tables
45111
+ if (tableZone.left === zone.left && tableZone.top === zone.top) {
45112
+ return table;
45113
+ }
45114
+ }
45115
+ return undefined;
45116
+ }
45056
45117
  checkUpdatedTableZoneIsValid(cmd) {
45057
45118
  if (!cmd.newTableRange) {
45058
45119
  return "Success" /* CommandResult.Success */;
@@ -45062,7 +45123,11 @@ class TablePlugin extends CorePlugin {
45062
45123
  if (zoneIsInSheet !== "Success" /* CommandResult.Success */) {
45063
45124
  return zoneIsInSheet;
45064
45125
  }
45065
- const overlappingTables = this.getTablesOverlappingZones(cmd.sheetId, [newTableZone]).filter((table) => !deepEquals(table.range.zone, cmd.zone));
45126
+ const updatedTable = this.getTableFromZone(cmd.sheetId, cmd.zone);
45127
+ if (!updatedTable) {
45128
+ return "TableNotFound" /* CommandResult.TableNotFound */;
45129
+ }
45130
+ const overlappingTables = this.getTablesOverlappingZones(cmd.sheetId, [newTableZone]).filter((table) => table.id !== updatedTable.id);
45066
45131
  return overlappingTables.length ? "TableOverlap" /* CommandResult.TableOverlap */ : "Success" /* CommandResult.Success */;
45067
45132
  }
45068
45133
  checkTableConfigUpdateIsValid(config) {
@@ -45080,7 +45145,7 @@ class TablePlugin extends CorePlugin {
45080
45145
  }
45081
45146
  return "Success" /* CommandResult.Success */;
45082
45147
  }
45083
- createTable(id, tableRange, config, filters) {
45148
+ createStaticTable(id, type, tableRange, config, filters) {
45084
45149
  const zone = tableRange.zone;
45085
45150
  if (!filters) {
45086
45151
  filters = [];
@@ -45095,9 +45160,51 @@ class TablePlugin extends CorePlugin {
45095
45160
  range: tableRange,
45096
45161
  filters,
45097
45162
  config,
45163
+ type,
45164
+ };
45165
+ }
45166
+ createDynamicTable(id, tableRange, config) {
45167
+ const zone = zoneToTopLeft(tableRange.zone);
45168
+ return {
45169
+ id,
45170
+ range: this.getters.getRangeFromZone(tableRange.sheetId, zone),
45171
+ config,
45172
+ type: "dynamic",
45098
45173
  };
45099
45174
  }
45100
- updateTable(table, newRange, configUpdate) {
45175
+ updateTable(cmd) {
45176
+ const table = this.getTableFromZone(cmd.sheetId, cmd.zone);
45177
+ if (!table) {
45178
+ return;
45179
+ }
45180
+ const newTableRange = cmd.newTableRange
45181
+ ? this.getters.getRangeFromRangeData(cmd.newTableRange)
45182
+ : undefined;
45183
+ if (newTableRange) {
45184
+ const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, newTableRange.zone);
45185
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
45186
+ }
45187
+ const range = newTableRange || table.range;
45188
+ const newConfig = this.updateTableConfig(cmd.config, table.config);
45189
+ const newTableType = cmd.tableType ?? table.type;
45190
+ if ((newTableType === "dynamic" && table.type !== "dynamic") ||
45191
+ (newTableType !== "dynamic" && table.type === "dynamic")) {
45192
+ const newTable = newTableType === "dynamic"
45193
+ ? this.createDynamicTable(table.id, range, newConfig)
45194
+ : this.createStaticTable(table.id, newTableType, range, newConfig);
45195
+ this.history.update("tables", cmd.sheetId, table.id, newTable);
45196
+ }
45197
+ else {
45198
+ const updatedTable = table.type === "dynamic"
45199
+ ? this.updateDynamicTable(table, range, newConfig)
45200
+ : this.updateStaticTable(table, range, newConfig, newTableType);
45201
+ this.history.update("tables", cmd.sheetId, table.id, updatedTable);
45202
+ }
45203
+ }
45204
+ updateStaticTable(table, newRange, configUpdate, newTableType = table.type) {
45205
+ if (newTableType === "dynamic") {
45206
+ throw new Error("Cannot use updateStaticTable to update a dynamic table");
45207
+ }
45101
45208
  const tableRange = newRange ? newRange : table.range;
45102
45209
  const tableZone = tableRange.zone;
45103
45210
  const newConfig = this.updateTableConfig(configUpdate, table.config);
@@ -45118,8 +45225,16 @@ class TablePlugin extends CorePlugin {
45118
45225
  range: tableRange,
45119
45226
  config,
45120
45227
  filters: filters.length ? filters : table.filters,
45228
+ type: newTableType,
45121
45229
  };
45122
45230
  }
45231
+ updateDynamicTable(table, newRange, newConfig) {
45232
+ const range = newRange
45233
+ ? this.getters.getRangeFromZone(newRange.sheetId, zoneToTopLeft(newRange.zone))
45234
+ : table.range;
45235
+ const config = newConfig ? newConfig : table.config;
45236
+ return { ...table, range, config };
45237
+ }
45123
45238
  /**
45124
45239
  * Update the old config of a table with the new partial config from an UpdateTable command.
45125
45240
  *
@@ -45141,35 +45256,29 @@ class TablePlugin extends CorePlugin {
45141
45256
  }
45142
45257
  createFilterFromZone(id, sheetId, zone, config) {
45143
45258
  const range = this.getters.getRangeFromZone(sheetId, zone);
45144
- return this.createFilter(id, range, config);
45145
- }
45146
- createFilter(id, range, config) {
45147
- const zone = range.zone;
45148
- if (zone.left !== zone.right) {
45149
- throw new Error("Can only define a filter on a single column");
45150
- }
45151
- const contentZone = getTableContentZone(zone, config);
45152
- const filteredRange = contentZone
45153
- ? this.getters.getRangeFromZone(range.sheetId, contentZone)
45154
- : undefined;
45155
- return {
45156
- id,
45157
- rangeWithHeaders: range,
45158
- col: zone.left,
45159
- filteredRange,
45160
- };
45259
+ return createFilter(id, range, config, this.getters.getRangeFromZone);
45161
45260
  }
45162
- copyTableForSheet(sheetId, table) {
45261
+ copyStaticTableForSheet(sheetId, table) {
45163
45262
  const newRange = this.getters.getRangeFromZone(sheetId, table.range.zone);
45164
45263
  const newFilters = table.filters.map((filter) => {
45165
45264
  const newFilterRange = this.getters.getRangeFromZone(sheetId, filter.rangeWithHeaders.zone);
45166
- return this.createFilter(filter.id, newFilterRange, table.config);
45265
+ return createFilter(filter.id, newFilterRange, table.config, this.getters.getRangeFromZone);
45167
45266
  });
45168
45267
  return {
45169
45268
  id: table.id,
45170
45269
  range: newRange,
45171
45270
  filters: newFilters,
45172
45271
  config: deepCopy(table.config),
45272
+ type: table.type,
45273
+ };
45274
+ }
45275
+ copyDynamicTableForSheet(sheetId, table) {
45276
+ const newRange = this.getters.getRangeFromZone(sheetId, table.range.zone);
45277
+ return {
45278
+ id: table.id,
45279
+ range: newRange,
45280
+ config: deepCopy(table.config),
45281
+ type: "dynamic",
45173
45282
  };
45174
45283
  }
45175
45284
  applyRangeChangeOnTable(sheetId, table, applyChange) {
@@ -45184,6 +45293,11 @@ class TablePlugin extends CorePlugin {
45184
45293
  default:
45185
45294
  newTableRange = tableRangeChange.range;
45186
45295
  }
45296
+ if (table.type === "dynamic") {
45297
+ const newTable = this.updateDynamicTable(table, newTableRange);
45298
+ this.history.update("tables", sheetId, table.id, newTable);
45299
+ return;
45300
+ }
45187
45301
  const filters = [];
45188
45302
  for (const filter of table.filters) {
45189
45303
  const filterRangeChange = applyChange(filter.rangeWithHeaders);
@@ -45195,7 +45309,7 @@ class TablePlugin extends CorePlugin {
45195
45309
  break;
45196
45310
  default:
45197
45311
  const newFilterRange = filterRangeChange.range;
45198
- const newFilter = this.createFilter(filter.id, newFilterRange, table.config);
45312
+ const newFilter = createFilter(filter.id, newFilterRange, table.config, this.getters.getRangeFromZone);
45199
45313
  filters.push(newFilter);
45200
45314
  }
45201
45315
  }
@@ -45210,7 +45324,7 @@ class TablePlugin extends CorePlugin {
45210
45324
  }
45211
45325
  filters.sort((f1, f2) => f1.col - f2.col);
45212
45326
  }
45213
- const newTable = this.createTable(table.id, newTableRange, table.config, filters);
45327
+ const newTable = this.createStaticTable(table.id, table.type, newTableRange, table.config, filters);
45214
45328
  this.history.update("tables", sheetId, table.id, newTable);
45215
45329
  }
45216
45330
  // ---------------------------------------------------------------------------
@@ -45221,16 +45335,20 @@ class TablePlugin extends CorePlugin {
45221
45335
  for (const tableData of sheet.tables || []) {
45222
45336
  const uuid = this.uuidGenerator.uuidv4();
45223
45337
  const tableConfig = tableData.config || DEFAULT_TABLE_CONFIG;
45224
- const tableRange = this.getters.getRangeFromSheetXC(sheet.id, tableData.range);
45225
- const table = this.createTable(uuid, tableRange, tableConfig);
45338
+ const range = this.getters.getRangeFromSheetXC(sheet.id, tableData.range);
45339
+ const tableType = tableData.type || "static";
45340
+ const table = tableType === "dynamic"
45341
+ ? this.createDynamicTable(uuid, range, tableConfig)
45342
+ : this.createStaticTable(uuid, tableType, range, tableConfig);
45226
45343
  this.history.update("tables", sheet.id, table.id, table);
45227
45344
  }
45228
45345
  }
45229
45346
  }
45230
45347
  export(data) {
45231
45348
  for (const sheet of data.sheets) {
45232
- for (const table of this.getTables(sheet.id)) {
45233
- const tableData = { range: zoneToXc(table.range.zone) };
45349
+ for (const table of this.getCoreTables(sheet.id)) {
45350
+ const range = zoneToXc(table.range.zone);
45351
+ const tableData = { range, type: table.type };
45234
45352
  if (!deepEquals(table.config, DEFAULT_TABLE_CONFIG)) {
45235
45353
  tableData.config = table.config;
45236
45354
  }
@@ -46946,14 +47064,18 @@ class Evaluator {
46946
47064
  if (!this.spreadingRelations.isArrayFormula(position)) {
46947
47065
  return [];
46948
47066
  }
46949
- return Array.from(this.spreadingRelations.getArrayResultPositions(position));
47067
+ if (this.evaluatedCells.get(position)?.type === CellValueType.error) {
47068
+ return [position];
47069
+ }
47070
+ const spreadPositions = Array.from(this.spreadingRelations.getArrayResultPositions(position));
47071
+ return [position, ...spreadPositions];
46950
47072
  }
46951
47073
  getEvaluatedPositions() {
46952
47074
  return this.evaluatedCells.keys();
46953
47075
  }
46954
47076
  getArrayFormulaSpreadingOn(position) {
46955
47077
  if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
46956
- return undefined;
47078
+ return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
46957
47079
  }
46958
47080
  const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
46959
47081
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
@@ -47082,6 +47204,7 @@ class Evaluator {
47082
47204
  if (!this.blockedArrayFormulas.has(position)) {
47083
47205
  this.invalidateSpreading(position);
47084
47206
  }
47207
+ this.spreadingRelations.removeNode(position);
47085
47208
  const cell = this.getters.getCell(position);
47086
47209
  if (cell === undefined) {
47087
47210
  return EMPTY_CELL;
@@ -47192,7 +47315,6 @@ class Evaluator {
47192
47315
  this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
47193
47316
  this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
47194
47317
  }
47195
- this.spreadingRelations.removeNode(position);
47196
47318
  }
47197
47319
  // ----------------------------------------------------------
47198
47320
  // COMMON FUNCTIONALITY
@@ -48290,6 +48412,181 @@ class EvaluationDataValidationPlugin extends UIPlugin {
48290
48412
  }
48291
48413
  }
48292
48414
 
48415
+ class DynamicTablesPlugin extends UIPlugin {
48416
+ static getters = [
48417
+ "canCreateDynamicTableOnZones",
48418
+ "doesZonesContainFilter",
48419
+ "getFilter",
48420
+ "getFilters",
48421
+ "getTable",
48422
+ "getTables",
48423
+ "getTablesOverlappingZones",
48424
+ "getFilterId",
48425
+ "getFilterHeaders",
48426
+ "isFilterHeader",
48427
+ ];
48428
+ tables = {};
48429
+ handle(cmd) {
48430
+ if (invalidateEvaluationCommands.has(cmd.type) ||
48431
+ (cmd.type === "UPDATE_CELL" && "content" in cmd) ||
48432
+ cmd.type === "EVALUATE_CELLS") {
48433
+ this.tables = {};
48434
+ return;
48435
+ }
48436
+ switch (cmd.type) {
48437
+ case "CREATE_TABLE":
48438
+ case "REMOVE_TABLE":
48439
+ case "UPDATE_TABLE":
48440
+ case "DELETE_CONTENT":
48441
+ this.tables = {};
48442
+ break;
48443
+ }
48444
+ }
48445
+ finalize() {
48446
+ for (const sheetId of this.getters.getSheetIds()) {
48447
+ if (!this.tables[sheetId]) {
48448
+ this.tables[sheetId] = this.computeTables(sheetId);
48449
+ }
48450
+ }
48451
+ }
48452
+ computeTables(sheetId) {
48453
+ const tables = [];
48454
+ const coreTables = this.getters.getCoreTables(sheetId);
48455
+ // First we create the static tables, so we can use them to compute collision with dynamic tables
48456
+ for (const table of coreTables) {
48457
+ if (table.type === "dynamic")
48458
+ continue;
48459
+ tables.push(table);
48460
+ }
48461
+ const staticTables = [...tables];
48462
+ // Then we create the dynamic tables
48463
+ for (const coreTable of coreTables) {
48464
+ if (coreTable.type !== "dynamic")
48465
+ continue;
48466
+ const table = this.coreTableToTable(sheetId, coreTable);
48467
+ let tableZone = table.range.zone;
48468
+ // Reduce the zone to avoid collision with static tables. Per design, dynamic tables can't overlap with other
48469
+ // dynamic tables, because formulas cannot spread on the same area, so we don't need to check for that.
48470
+ for (const staticTable of staticTables) {
48471
+ if (overlap(tableZone, staticTable.range.zone)) {
48472
+ tableZone = { ...tableZone, right: staticTable.range.zone.left - 1 };
48473
+ }
48474
+ }
48475
+ tables.push({ ...table, range: this.getters.getRangeFromZone(sheetId, tableZone) });
48476
+ }
48477
+ return tables;
48478
+ }
48479
+ getFilters(sheetId) {
48480
+ return this.getTables(sheetId)
48481
+ .filter((table) => table.config.hasFilters)
48482
+ .map((table) => table.filters)
48483
+ .flat();
48484
+ }
48485
+ getTables(sheetId) {
48486
+ return this.tables[sheetId] || [];
48487
+ }
48488
+ getFilter(position) {
48489
+ const table = this.getTable(position);
48490
+ if (!table || !table.config.hasFilters) {
48491
+ return undefined;
48492
+ }
48493
+ return table.filters.find((filter) => filter.col === position.col);
48494
+ }
48495
+ getFilterId(position) {
48496
+ return this.getFilter(position)?.id;
48497
+ }
48498
+ getTable({ sheetId, col, row }) {
48499
+ return this.getTables(sheetId).find((table) => isInside(col, row, table.range.zone));
48500
+ }
48501
+ getTablesOverlappingZones(sheetId, zones) {
48502
+ return this.getTables(sheetId).filter((table) => zones.some((zone) => overlap(table.range.zone, zone)));
48503
+ }
48504
+ doesZonesContainFilter(sheetId, zones) {
48505
+ return this.getTablesOverlappingZones(sheetId, zones).some((table) => table.config.hasFilters);
48506
+ }
48507
+ getFilterHeaders(sheetId) {
48508
+ const headers = [];
48509
+ for (const table of this.getTables(sheetId)) {
48510
+ if (!table.config.hasFilters) {
48511
+ continue;
48512
+ }
48513
+ const zone = table.range.zone;
48514
+ const row = zone.top;
48515
+ for (let col = zone.left; col <= zone.right; col++) {
48516
+ headers.push({ sheetId, col, row });
48517
+ }
48518
+ }
48519
+ return headers;
48520
+ }
48521
+ isFilterHeader({ sheetId, col, row }) {
48522
+ const headers = this.getFilterHeaders(sheetId);
48523
+ return headers.some((header) => header.col === col && header.row === row);
48524
+ }
48525
+ /**
48526
+ * Check if we can create a dynamic table on the given zones.
48527
+ * - The zones must be continuous
48528
+ * - The union of the zones must be either:
48529
+ * - A single cell that contains an array formula
48530
+ * - All the spread cells of a single array formula
48531
+ */
48532
+ canCreateDynamicTableOnZones(sheetId, zones) {
48533
+ if (!areZonesContinuous(zones)) {
48534
+ return false;
48535
+ }
48536
+ const unionZone = union(...zones);
48537
+ const topLeft = { col: unionZone.left, row: unionZone.top, sheetId };
48538
+ const parentSpreadingCell = this.getters.getArrayFormulaSpreadingOn(topLeft);
48539
+ if (!parentSpreadingCell) {
48540
+ return false;
48541
+ }
48542
+ else if (deepEquals(parentSpreadingCell, topLeft) && getZoneArea(unionZone) === 1) {
48543
+ return true;
48544
+ }
48545
+ const spreadPositions = this.getters.getSpreadPositionsOf(parentSpreadingCell);
48546
+ return deepEquals(unionZone, unionPositionsToZone(spreadPositions));
48547
+ }
48548
+ coreTableToTable(sheetId, table) {
48549
+ if (table.type !== "dynamic") {
48550
+ return table;
48551
+ }
48552
+ const tableZone = table.range.zone;
48553
+ const tablePosition = { sheetId, col: tableZone.left, row: tableZone.top };
48554
+ const spreadPositions = this.getters.getSpreadPositionsOf(tablePosition);
48555
+ const zone = spreadPositions.length ? unionPositionsToZone(spreadPositions) : table.range.zone;
48556
+ const range = this.getters.getRangeFromZone(sheetId, zone);
48557
+ const filters = this.getDynamicTableFilters(sheetId, table, zone);
48558
+ return { id: table.id, range, filters, config: table.config };
48559
+ }
48560
+ getDynamicTableFilters(sheetId, table, tableZone) {
48561
+ const filters = [];
48562
+ const { top, bottom, left, right } = tableZone;
48563
+ for (let col = left; col <= right; col++) {
48564
+ const tableColIndex = col - left;
48565
+ const zone = { left: col, right: col, top, bottom };
48566
+ const filter = createFilter(this.getDynamicTableFilterId(table.id, tableColIndex), this.getters.getRangeFromZone(sheetId, zone), table.config, this.getters.getRangeFromZone);
48567
+ filters.push(filter);
48568
+ }
48569
+ return filters;
48570
+ }
48571
+ getDynamicTableFilterId(tableId, tableCol) {
48572
+ return tableId + "_" + tableCol;
48573
+ }
48574
+ exportForExcel(data) {
48575
+ for (const sheet of data.sheets) {
48576
+ for (const tableData of sheet.tables) {
48577
+ const zone = toZone(tableData.range);
48578
+ const topLeft = { sheetId: sheet.id, col: zone.left, row: zone.top };
48579
+ const coreTable = this.getters.getCoreTable(topLeft);
48580
+ const table = this.getTable(topLeft);
48581
+ if (coreTable?.type !== "dynamic" || !table) {
48582
+ continue;
48583
+ }
48584
+ tableData.range = zoneToXc(table.range.zone);
48585
+ }
48586
+ }
48587
+ }
48588
+ }
48589
+
48293
48590
  class HeaderSizeUIPlugin extends UIPlugin {
48294
48591
  static getters = ["getRowSize", "getHeaderSize"];
48295
48592
  tallestCellInRow = {};
@@ -51337,10 +51634,11 @@ class TableAutofillPlugin extends UIPlugin {
51337
51634
  handle(cmd) {
51338
51635
  switch (cmd.type) {
51339
51636
  case "AUTOFILL_TABLE_COLUMN":
51340
- const table = this.getters.getTable(cmd);
51637
+ const table = this.getters.getCoreTable(cmd);
51341
51638
  const cell = this.getters.getCell(cmd);
51342
- if (!table || !table.config.automaticAutofill || !cell?.isFormula)
51639
+ if (!table?.config.automaticAutofill || table.type === "dynamic" || !cell?.isFormula) {
51343
51640
  return;
51641
+ }
51344
51642
  const { col, row } = cmd;
51345
51643
  const tableContentZone = getTableContentZone(table.range.zone, table.config);
51346
51644
  if (tableContentZone && isInside(col, row, tableContentZone)) {
@@ -52069,9 +52367,6 @@ class FilterEvaluationPlugin extends UIPlugin {
52069
52367
  case "START":
52070
52368
  for (const sheetId of this.getters.getSheetIds()) {
52071
52369
  this.filterValues[sheetId] = {};
52072
- for (const filter of this.getters.getFilters(sheetId)) {
52073
- this.filterValues[sheetId][filter.id] = [];
52074
- }
52075
52370
  }
52076
52371
  break;
52077
52372
  case "CREATE_SHEET":
@@ -52092,16 +52387,7 @@ class FilterEvaluationPlugin extends UIPlugin {
52092
52387
  this.updateHiddenRows();
52093
52388
  break;
52094
52389
  case "DUPLICATE_SHEET":
52095
- const filterValues = {};
52096
- for (const newFilter of this.getters.getFilters(cmd.sheetIdTo)) {
52097
- const zone = newFilter.rangeWithHeaders.zone;
52098
- filterValues[newFilter.id] = this.getFilterHiddenValues({
52099
- sheetId: cmd.sheetId,
52100
- col: zone.left,
52101
- row: zone.top,
52102
- });
52103
- }
52104
- this.filterValues[cmd.sheetIdTo] = filterValues;
52390
+ this.filterValues[cmd.sheetIdTo] = deepCopy(this.filterValues[cmd.sheetId]);
52105
52391
  break;
52106
52392
  // If we don't handle DELETE_SHEET, on one hand we will have some residual data, on the other hand we keep the data
52107
52393
  // on DELETE_SHEET followed by undo
@@ -54045,8 +54331,9 @@ const coreViewsPluginRegistry = new Registry()
54045
54331
  .add("evaluation_chart", EvaluationChartPlugin)
54046
54332
  .add("evaluation_cf", EvaluationConditionalFormatPlugin)
54047
54333
  .add("row_size", HeaderSizeUIPlugin)
54048
- .add("custom_colors", CustomColorsPlugin)
54049
- .add("data_validation_ui", EvaluationDataValidationPlugin);
54334
+ .add("data_validation_ui", EvaluationDataValidationPlugin)
54335
+ .add("dynamic_tables", DynamicTablesPlugin)
54336
+ .add("custom_colors", CustomColorsPlugin);
54050
54337
 
54051
54338
  const clickableCellRegistry = new Registry();
54052
54339
  clickableCellRegistry.add("link", {
@@ -60177,6 +60464,6 @@ exports.tokenColors = tokenColors;
60177
60464
  exports.tokenize = tokenize;
60178
60465
 
60179
60466
 
60180
- __info__.version = "17.2.1";
60181
- __info__.date = "2024-03-25T09:41:58.737Z";
60182
- __info__.hash = "f97284c";
60467
+ __info__.version = "17.3.0-alpha.1";
60468
+ __info__.date = "2024-03-25T09:43:36.072Z";
60469
+ __info__.hash = "4095c41";