@odoo/o-spreadsheet 17.2.0-alpha.4 → 17.2.0-alpha.5

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.0-alpha.4
7
- * @date 2024-02-09T13:10:23.460Z
8
- * @hash 1b33cf4
6
+ * @version 17.2.0-alpha.5
7
+ * @date 2024-02-16T14:27:52.323Z
8
+ * @hash 0c69dd8
9
9
  */
10
10
 
11
11
  'use strict';
@@ -455,8 +455,8 @@ function isObjectEmptyRecursive(argument) {
455
455
  * If the given item does not exist in the dictionary, it creates one with a new id.
456
456
  */
457
457
  function getItemId(item, itemsDic) {
458
- for (let [key, value] of Object.entries(itemsDic)) {
459
- if (deepEquals(value, item)) {
458
+ for (const key in itemsDic) {
459
+ if (deepEquals(itemsDic[key], item)) {
460
460
  return parseInt(key, 10);
461
461
  }
462
462
  }
@@ -560,11 +560,13 @@ function deepEquals(o1, o2) {
560
560
  if (typeof o1 !== "object")
561
561
  return o1 === o2;
562
562
  // Objects can have different keys if the values are undefined
563
- const keys = new Set();
564
- Object.keys(o1).forEach((key) => keys.add(key));
565
- Object.keys(o2).forEach((key) => keys.add(key));
566
- for (let key of keys) {
567
- if (typeof o1[key] !== typeof o1[key])
563
+ for (const key in o2) {
564
+ if (!(key in o1) && o2[key] !== undefined) {
565
+ return false;
566
+ }
567
+ }
568
+ for (const key in o1) {
569
+ if (typeof o1[key] !== typeof o2[key])
568
570
  return false;
569
571
  if (typeof o1[key] === "object") {
570
572
  if (!deepEquals(o1[key], o2[key]))
@@ -634,18 +636,18 @@ function isConsecutive(iterable) {
634
636
  return true;
635
637
  }
636
638
  class JetSet extends Set {
637
- add(...iterable) {
639
+ addMany(iterable) {
638
640
  for (const element of iterable) {
639
641
  super.add(element);
640
642
  }
641
643
  return this;
642
644
  }
643
- delete(...iterable) {
644
- let deleted = false;
645
+ deleteMany(iterable) {
646
+ let wasDeleted = false;
645
647
  for (const element of iterable) {
646
- deleted ||= super.delete(element);
648
+ wasDeleted ||= super.delete(element);
647
649
  }
648
- return deleted;
650
+ return wasDeleted;
649
651
  }
650
652
  }
651
653
  /**
@@ -1947,7 +1949,7 @@ class DispatchResult {
1947
1949
  * Static helper which returns a successful DispatchResult
1948
1950
  */
1949
1951
  static get Success() {
1950
- return new DispatchResult();
1952
+ return SUCCESS;
1951
1953
  }
1952
1954
  get isSuccessful() {
1953
1955
  return this.reasons.length === 0;
@@ -1960,6 +1962,7 @@ class DispatchResult {
1960
1962
  return this.reasons.includes(reason);
1961
1963
  }
1962
1964
  }
1965
+ const SUCCESS = new DispatchResult();
1963
1966
  exports.CommandResult = void 0;
1964
1967
  (function (CommandResult) {
1965
1968
  CommandResult["Success"] = "Success";
@@ -2266,7 +2269,7 @@ const normalizeString = memoize(function normalizeString(str) {
2266
2269
  .normalize("NFD")
2267
2270
  .replace(/[\u0300-\u036f]/g, "");
2268
2271
  });
2269
- const expectBooleanValueError = (value) => _t("The function [[FUNCTION_NAME]] expects a boolean value, but '%s' is a text, and cannot be coerced to a number.", value);
2272
+ const expectBooleanValueError = (value) => _t("The function [[FUNCTION_NAME]] expects a boolean value, but '%s' is a text, and cannot be coerced to a boolean.", value);
2270
2273
  function toBoolean(data) {
2271
2274
  const value = toValue(data);
2272
2275
  switch (typeof value) {
@@ -7530,6 +7533,9 @@ class DependencyContainer {
7530
7533
  * Also useful for mocking a store.
7531
7534
  */
7532
7535
  inject(Store, instance) {
7536
+ if (this.dependencies.has(Store) && this.dependencies.get(Store) !== instance) {
7537
+ throw new Error(`Store ${Store.name} already has an instance`);
7538
+ }
7533
7539
  this.dependencies.set(Store, instance);
7534
7540
  }
7535
7541
  /**
@@ -11358,8 +11364,10 @@ class ChartFigure extends owl.Component {
11358
11364
  };
11359
11365
  static components = {};
11360
11366
  onDoubleClick() {
11361
- this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
11362
- this.env.openSidePanel("ChartPanel");
11367
+ const result = this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
11368
+ if (result.isSuccessful) {
11369
+ this.env.openSidePanel("ChartPanel");
11370
+ }
11363
11371
  }
11364
11372
  get chartType() {
11365
11373
  return this.env.model.getters.getChartType(this.props.figure.id);
@@ -13916,6 +13924,12 @@ const INSERT_LINK = (env) => {
13916
13924
  let { col, row } = env.model.getters.getActivePosition();
13917
13925
  env.getStore(CellPopoverStore).open({ col, row }, "LinkEditor");
13918
13926
  };
13927
+ const INSERT_LINK_NAME = (env) => {
13928
+ const sheetId = env.model.getters.getActiveSheetId();
13929
+ const { col, row } = env.model.getters.getActivePosition();
13930
+ const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
13931
+ return cell && cell.link ? _t("Edit link") : _t("Insert link");
13932
+ };
13919
13933
  //------------------------------------------------------------------------------
13920
13934
  // Filters action
13921
13935
  //------------------------------------------------------------------------------
@@ -21722,6 +21736,68 @@ const INDEX = {
21722
21736
  isExported: true,
21723
21737
  };
21724
21738
  // -----------------------------------------------------------------------------
21739
+ // INDEX
21740
+ // -----------------------------------------------------------------------------
21741
+ const INDIRECT = {
21742
+ description: _t("Returns the content of a cell, specified by a string."),
21743
+ args: [
21744
+ arg("reference (string)", _t("The range of cells from which the values are returned.")),
21745
+ arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
21746
+ ],
21747
+ returns: ["ANY"],
21748
+ compute: function (reference, useA1Notation = { value: true }) {
21749
+ let _reference = reference?.value?.toString();
21750
+ if (!_reference) {
21751
+ throw new InvalidReferenceError(_t("Reference should be defined."));
21752
+ }
21753
+ const _useA1Notation = toBoolean(useA1Notation);
21754
+ if (!_useA1Notation) {
21755
+ throw new EvaluationError(_t("R1C1 notation is not supported."));
21756
+ }
21757
+ const sheetId = this.__originSheetId;
21758
+ let originPosition;
21759
+ const __originCellXC = this.__originCellXC?.();
21760
+ if (__originCellXC) {
21761
+ const cellZone = toZone(__originCellXC);
21762
+ originPosition = {
21763
+ sheetId,
21764
+ col: cellZone.left,
21765
+ row: cellZone.top,
21766
+ };
21767
+ // The following line is used to reset the dependencies of the cell, to avoid
21768
+ // keeping dependencies from previous evaluation of the INDIRECT formula (i.e.
21769
+ // in case the reference has been changed).
21770
+ this.updateDependencies?.(originPosition);
21771
+ }
21772
+ const range = this.getters.getRangeFromSheetXC(sheetId, _reference);
21773
+ if (range === undefined || range.invalidXc || range.invalidSheetName) {
21774
+ throw new InvalidReferenceError();
21775
+ }
21776
+ if (originPosition) {
21777
+ this.addDependencies?.(originPosition, [range]);
21778
+ }
21779
+ const values = [];
21780
+ for (let col = range.zone.left; col <= range.zone.right; col++) {
21781
+ const colValues = [];
21782
+ for (let row = range.zone.top; row <= range.zone.bottom; row++) {
21783
+ const position = { sheetId: range.sheetId, col, row };
21784
+ // The below 'value' is typed as CellValue because the evaluateFormula will have to
21785
+ // evaluate a string containing the A1 reference of a single cell, so this will
21786
+ // return a CellValue.
21787
+ const value = this.getters.evaluateFormula(range.sheetId, toXC(col, row));
21788
+ const evaluatedCell = this.getters.getEvaluatedCell(position);
21789
+ colValues.push({
21790
+ ...evaluatedCell,
21791
+ value,
21792
+ });
21793
+ }
21794
+ values.push(colValues);
21795
+ }
21796
+ return values.length === 1 && values[0].length === 1 ? values[0][0] : values;
21797
+ },
21798
+ isExported: true,
21799
+ };
21800
+ // -----------------------------------------------------------------------------
21725
21801
  // LOOKUP
21726
21802
  // -----------------------------------------------------------------------------
21727
21803
  const LOOKUP = {
@@ -21927,6 +22003,7 @@ var lookup = /*#__PURE__*/Object.freeze({
21927
22003
  COLUMNS: COLUMNS,
21928
22004
  HLOOKUP: HLOOKUP,
21929
22005
  INDEX: INDEX,
22006
+ INDIRECT: INDIRECT,
21930
22007
  LOOKUP: LOOKUP,
21931
22008
  MATCH: MATCH,
21932
22009
  ROW: ROW,
@@ -22902,7 +22979,7 @@ const insertImage = {
22902
22979
  };
22903
22980
  const insertFunction = {
22904
22981
  name: _t("Function"),
22905
- icon: "o-spreadsheet-Icon.SHOW_HIDE_FORMULA",
22982
+ icon: "o-spreadsheet-Icon.FORMULA",
22906
22983
  };
22907
22984
  const insertFunctionSum = {
22908
22985
  name: _t("SUM"),
@@ -23124,7 +23201,7 @@ cellMenuRegistry
23124
23201
  })
23125
23202
  .add("insert_link", {
23126
23203
  ...insertLink,
23127
- name: _t("Insert link"),
23204
+ name: INSERT_LINK_NAME,
23128
23205
  sequence: 150,
23129
23206
  separator: true,
23130
23207
  });
@@ -23789,9 +23866,7 @@ const freezeCurrentCol = {
23789
23866
  isReadonlyAllowed: true,
23790
23867
  };
23791
23868
  const viewGridlines = {
23792
- name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
23793
- ? _t("Hide gridlines")
23794
- : _t("Show gridlines"),
23869
+ name: _t("Gridlines"),
23795
23870
  execute: (env) => {
23796
23871
  const sheetId = env.model.getters.getActiveSheetId();
23797
23872
  env.model.dispatch("SET_GRID_LINES_VISIBILITY", {
@@ -23799,13 +23874,16 @@ const viewGridlines = {
23799
23874
  areGridLinesVisible: !env.model.getters.getGridLinesVisibility(sheetId),
23800
23875
  });
23801
23876
  },
23802
- icon: "o-spreadsheet-Icon.SHOW_HIDE_GRID",
23877
+ isActive: (env) => {
23878
+ const sheetId = env.model.getters.getActiveSheetId();
23879
+ return env.model.getters.getGridLinesVisibility(sheetId);
23880
+ },
23803
23881
  };
23804
23882
  const viewFormulas = {
23805
- name: (env) => env.model.getters.shouldShowFormulas() ? "Hide formulas" : _t("Show formulas"),
23883
+ name: _t("Formulas"),
23884
+ isActive: (env) => env.model.getters.shouldShowFormulas(),
23806
23885
  execute: (env) => env.model.dispatch("SET_FORMULA_VISIBILITY", { show: !env.model.getters.shouldShowFormulas() }),
23807
23886
  isReadonlyAllowed: true,
23808
- icon: "o-spreadsheet-Icon.SHOW_HIDE_FORMULA",
23809
23887
  };
23810
23888
  const createRemoveFilter = {
23811
23889
  name: (env) => selectionContainsFilter(env) ? _t("Remove selected filters") : _t("Create filter"),
@@ -24362,13 +24440,18 @@ topbarMenuRegistry
24362
24440
  isVisible: (env) => canUngroupHeaders(env, "ROW"),
24363
24441
  sequence: 20,
24364
24442
  })
24365
- .addChild("view_gridlines", ["view"], {
24443
+ .addChild("show", ["view"], {
24444
+ name: _t("Show"),
24445
+ sequence: 1,
24446
+ icon: "o-spreadsheet-Icon.SHOW",
24447
+ })
24448
+ .addChild("view_gridlines", ["view", "show"], {
24366
24449
  ...viewGridlines,
24367
- sequence: 15,
24450
+ sequence: 5,
24368
24451
  })
24369
- .addChild("view_formulas", ["view"], {
24452
+ .addChild("view_formulas", ["view", "show"], {
24370
24453
  ...viewFormulas,
24371
- sequence: 20,
24454
+ sequence: 10,
24372
24455
  })
24373
24456
  // ---------------------------------------------------------------------
24374
24457
  // INSERT MENU ITEMS
@@ -25351,6 +25434,17 @@ class TextValueProvider extends owl.Component {
25351
25434
  onValueSelected: Function,
25352
25435
  onValueHovered: Function,
25353
25436
  };
25437
+ autoCompleteListRef = owl.useRef("autoCompleteList");
25438
+ setup() {
25439
+ owl.useEffect(() => {
25440
+ const selectedIndex = this.props.selectedIndex;
25441
+ if (selectedIndex === undefined) {
25442
+ return;
25443
+ }
25444
+ const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
25445
+ selectedElement?.scrollIntoView?.({ block: "nearest" });
25446
+ }, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
25447
+ }
25354
25448
  }
25355
25449
 
25356
25450
  class ContentEditableHelper {
@@ -25795,6 +25889,7 @@ css /* scss */ `
25795
25889
  position: absolute;
25796
25890
  margin: 1px 4px;
25797
25891
  pointer-events: none;
25892
+ overflow: auto;
25798
25893
 
25799
25894
  .o-semi-bold {
25800
25895
  /** FIXME: to remove in favor of Bootstrap
@@ -25854,7 +25949,10 @@ class Composer extends owl.Component {
25854
25949
  if (this.props.delimitation && this.props.rect) {
25855
25950
  const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
25856
25951
  const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
25952
+ assistantStyle["max-height"] = `${remainingHeight}px`;
25857
25953
  if (cellY > remainingHeight) {
25954
+ const availableSpaceAbove = cellY;
25955
+ assistantStyle["max-height"] = `${availableSpaceAbove}px`;
25858
25956
  // render top
25859
25957
  // We compensate 2 px of margin on the assistant style + 1px for design reasons
25860
25958
  assistantStyle.top = `-3px`;
@@ -29459,6 +29557,34 @@ class VerticalScrollBar extends owl.Component {
29459
29557
  }
29460
29558
  }
29461
29559
 
29560
+ class SidePanelStore extends SpreadsheetStore {
29561
+ isOpen = false;
29562
+ panelProps = {};
29563
+ componentTag = "";
29564
+ open(componentTag, panelProps = {}) {
29565
+ if (this.isOpen && componentTag !== this.componentTag) {
29566
+ this.panelProps?.onCloseSidePanel?.();
29567
+ }
29568
+ this.componentTag = componentTag;
29569
+ this.panelProps = panelProps;
29570
+ this.isOpen = true;
29571
+ }
29572
+ toggle(componentTag, panelProps) {
29573
+ if (this.isOpen && componentTag === this.componentTag) {
29574
+ this.close();
29575
+ }
29576
+ else {
29577
+ this.open(componentTag, panelProps);
29578
+ }
29579
+ }
29580
+ close() {
29581
+ this.panelProps.onCloseSidePanel?.();
29582
+ this.isOpen = false;
29583
+ this.panelProps = {};
29584
+ this.componentTag = "";
29585
+ }
29586
+ }
29587
+
29462
29588
  const registries$1 = {
29463
29589
  ROW: rowMenuRegistry,
29464
29590
  COL: colMenuRegistry,
@@ -29472,7 +29598,6 @@ const registries$1 = {
29472
29598
  class Grid extends owl.Component {
29473
29599
  static template = "o-spreadsheet-Grid";
29474
29600
  static props = {
29475
- sidePanelIsOpen: Boolean,
29476
29601
  exposeFocus: Function,
29477
29602
  };
29478
29603
  static components = {
@@ -29501,6 +29626,7 @@ class Grid extends owl.Component {
29501
29626
  onMouseWheel;
29502
29627
  canvasPosition;
29503
29628
  hoveredCell;
29629
+ sidePanel;
29504
29630
  setup() {
29505
29631
  this.highlightStore = useStore(HighlightStore);
29506
29632
  this.menuState = owl.useState({
@@ -29514,6 +29640,7 @@ class Grid extends owl.Component {
29514
29640
  this.composerStore = useStore(ComposerStore);
29515
29641
  this.composerFocusStore = useStore(ComposerFocusStore);
29516
29642
  this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
29643
+ this.sidePanel = useStore(SidePanelStore);
29517
29644
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
29518
29645
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
29519
29646
  owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
@@ -29526,6 +29653,11 @@ class Grid extends owl.Component {
29526
29653
  this.hoveredCell.clear();
29527
29654
  });
29528
29655
  this.cellPopovers = useStore(CellPopoverStore);
29656
+ owl.useEffect(() => {
29657
+ if (!this.sidePanel.isOpen) {
29658
+ this.DOMFocusableElementStore.focus();
29659
+ }
29660
+ }, () => [this.sidePanel.isOpen]);
29529
29661
  }
29530
29662
  onCellHovered({ col, row }) {
29531
29663
  this.hoveredCell.hover({ col, row });
@@ -30902,6 +31034,7 @@ class Checkbox extends owl.Component {
30902
31034
  value: { type: Boolean, optional: true },
30903
31035
  className: { type: String, optional: true },
30904
31036
  name: { type: String, optional: true },
31037
+ title: { type: String, optional: true },
30905
31038
  onChange: Function,
30906
31039
  };
30907
31040
  static defaultProps = { value: false };
@@ -31913,6 +32046,35 @@ chartSidePanelComponentRegistry
31913
32046
  design: ScorecardChartDesignPanel,
31914
32047
  });
31915
32048
 
32049
+ class MainChartPanelStore extends SpreadsheetStore {
32050
+ sidePanel = this.get(SidePanelStore);
32051
+ figureId;
32052
+ panel = "configuration";
32053
+ constructor(get, figureId) {
32054
+ super(get);
32055
+ this.figureId = figureId;
32056
+ }
32057
+ handle(cmd) {
32058
+ switch (cmd.type) {
32059
+ case "DELETE_FIGURE":
32060
+ if (this.sidePanel.componentTag === "ChartPanel" && this.figureId === cmd.id) {
32061
+ this.sidePanel.close();
32062
+ }
32063
+ break;
32064
+ case "SELECT_FIGURE":
32065
+ if (cmd.id) {
32066
+ this.figureId = cmd.id;
32067
+ }
32068
+ else if (this.sidePanel.componentTag === "ChartPanel") {
32069
+ this.sidePanel.close();
32070
+ }
32071
+ }
32072
+ }
32073
+ activatePanel(panel) {
32074
+ this.panel = panel;
32075
+ }
32076
+ }
32077
+
31916
32078
  css /* scss */ `
31917
32079
  .o-chart {
31918
32080
  .o-panel {
@@ -31941,37 +32103,19 @@ class ChartPanel extends owl.Component {
31941
32103
  static template = "o-spreadsheet-ChartPanel";
31942
32104
  static components = { Section };
31943
32105
  static props = { onCloseSidePanel: Function };
31944
- state;
32106
+ store;
31945
32107
  get figureId() {
31946
- return this.state.figureId;
32108
+ return this.store.figureId;
31947
32109
  }
31948
32110
  setup() {
31949
- const selectedFigureId = this.env.model.getters.getSelectedFigureId();
31950
- if (!selectedFigureId) {
31951
- this.props.onCloseSidePanel();
31952
- return;
31953
- }
31954
- this.state = owl.useState({
31955
- panel: "configuration",
31956
- figureId: selectedFigureId,
31957
- });
31958
- owl.onWillUpdateProps(() => {
31959
- const selectedFigureId = this.env.model.getters.getSelectedFigureId();
31960
- if (selectedFigureId && selectedFigureId !== this.state.figureId) {
31961
- this.state.figureId = selectedFigureId;
31962
- }
31963
- if (!this.env.model.getters.isChartDefined(this.figureId)) {
31964
- this.props.onCloseSidePanel();
31965
- return;
31966
- }
31967
- });
32111
+ this.store = useLocalStore(MainChartPanelStore, this.env.model.getters.getSelectedFigureId());
31968
32112
  }
31969
32113
  updateChart(figureId, updateDefinition) {
31970
32114
  if (figureId !== this.figureId) {
31971
32115
  return;
31972
32116
  }
31973
32117
  const definition = {
31974
- ...this.getChartDefinition(),
32118
+ ...this.getChartDefinition(this.figureId),
31975
32119
  ...updateDefinition,
31976
32120
  };
31977
32121
  return this.env.model.dispatch("UPDATE_CHART", {
@@ -31985,7 +32129,7 @@ class ChartPanel extends owl.Component {
31985
32129
  return;
31986
32130
  }
31987
32131
  const definition = {
31988
- ...this.getChartDefinition(),
32132
+ ...this.getChartDefinition(this.figureId),
31989
32133
  ...updateDefinition,
31990
32134
  };
31991
32135
  return this.env.model.canDispatch("UPDATE_CHART", {
@@ -31995,6 +32139,9 @@ class ChartPanel extends owl.Component {
31995
32139
  });
31996
32140
  }
31997
32141
  onTypeChange(type) {
32142
+ if (!this.figureId) {
32143
+ return;
32144
+ }
31998
32145
  const context = this.env.model.getters.getContextCreationChart(this.figureId);
31999
32146
  if (!context) {
32000
32147
  throw new Error("Chart not defined.");
@@ -32007,6 +32154,9 @@ class ChartPanel extends owl.Component {
32007
32154
  });
32008
32155
  }
32009
32156
  get chartPanel() {
32157
+ if (!this.figureId) {
32158
+ throw new Error("Chart not defined.");
32159
+ }
32010
32160
  const type = this.env.model.getters.getChartType(this.figureId);
32011
32161
  if (!type) {
32012
32162
  throw new Error("Chart not defined.");
@@ -32017,15 +32167,12 @@ class ChartPanel extends owl.Component {
32017
32167
  }
32018
32168
  return chartPanel;
32019
32169
  }
32020
- getChartDefinition(figureId = this.figureId) {
32170
+ getChartDefinition(figureId) {
32021
32171
  return this.env.model.getters.getChartDefinition(figureId);
32022
32172
  }
32023
32173
  get chartTypes() {
32024
32174
  return getChartTypes();
32025
32175
  }
32026
- activatePanel(panel) {
32027
- this.state.panel = panel;
32028
- }
32029
32176
  }
32030
32177
 
32031
32178
  const BORDER_COLOR = "#8B008B";
@@ -32119,7 +32266,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
32119
32266
  }
32120
32267
  finalize() {
32121
32268
  if (this.isSearchDirty) {
32122
- this.refreshSearch();
32269
+ this.refreshSearch(false);
32123
32270
  this.isSearchDirty = false;
32124
32271
  }
32125
32272
  }
@@ -32151,10 +32298,10 @@ class FindAndReplaceStore extends SpreadsheetStore {
32151
32298
  /**
32152
32299
  * refresh the matches according to the current search options
32153
32300
  */
32154
- refreshSearch() {
32301
+ refreshSearch(jumpToMatchSheet = true) {
32155
32302
  this.selectedMatchIndex = null;
32156
32303
  this.findMatches();
32157
- this.selectNextCell(Direction.current);
32304
+ this.selectNextCell(Direction.current, jumpToMatchSheet);
32158
32305
  }
32159
32306
  getSheetsInSearchOrder() {
32160
32307
  switch (this.searchOptions.searchScope) {
@@ -32224,7 +32371,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
32224
32371
  * It is also used to keep coherence between the selected searchMatch
32225
32372
  * and selectedMatchIndex.
32226
32373
  */
32227
- selectNextCell(indexChange) {
32374
+ selectNextCell(indexChange, jumpToMatchSheet = true) {
32228
32375
  const matches = this.searchMatches;
32229
32376
  if (!matches.length) {
32230
32377
  this.selectedMatchIndex = null;
@@ -32250,7 +32397,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
32250
32397
  this.selectedMatchIndex = nextIndex;
32251
32398
  const selectedMatch = matches[nextIndex];
32252
32399
  // Switch to the sheet where the match is located
32253
- if (this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
32400
+ if (jumpToMatchSheet && this.getters.getActiveSheetId() !== selectedMatch.sheetId) {
32254
32401
  this.model.dispatch("ACTIVATE_SHEET", {
32255
32402
  sheetIdFrom: this.getters.getActiveSheetId(),
32256
32403
  sheetIdTo: selectedMatch.sheetId,
@@ -36967,22 +37114,7 @@ class BordersPlugin extends CorePlugin {
36967
37114
  }
36968
37115
  }
36969
37116
  export(data) {
36970
- // Borders
36971
- let borderId = 0;
36972
37117
  const borders = {};
36973
- /**
36974
- * Get the id of the given border. If the border does not exist, it creates
36975
- * one.
36976
- */
36977
- function getBorderId(border) {
36978
- for (let [key, value] of Object.entries(borders)) {
36979
- if (deepEquals(value, border)) {
36980
- return parseInt(key, 10);
36981
- }
36982
- }
36983
- borders[++borderId] = border;
36984
- return borderId;
36985
- }
36986
37118
  for (let sheet of data.sheets) {
36987
37119
  for (let col = 0; col < sheet.colNumber; col++) {
36988
37120
  for (let row = 0; row < sheet.rowNumber; row++) {
@@ -36990,7 +37122,7 @@ class BordersPlugin extends CorePlugin {
36990
37122
  if (border) {
36991
37123
  const xc = toXC(col, row);
36992
37124
  const cell = sheet.cells[xc];
36993
- const borderId = getBorderId(border);
37125
+ const borderId = getItemId(border, borders);
36994
37126
  if (cell) {
36995
37127
  cell.border = borderId;
36996
37128
  }
@@ -37687,9 +37819,9 @@ class CellPlugin extends CorePlugin {
37687
37819
  allowDispatch(cmd) {
37688
37820
  switch (cmd.type) {
37689
37821
  case "UPDATE_CELL":
37690
- return this.checkCellOutOfSheet(cmd);
37822
+ return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
37691
37823
  case "CLEAR_CELL":
37692
- return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
37824
+ return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
37693
37825
  default:
37694
37826
  return "Success" /* CommandResult.Success */;
37695
37827
  }
@@ -37859,8 +37991,8 @@ class CellPlugin extends CorePlugin {
37859
37991
  }
37860
37992
  removeDefaultStyleValues(style) {
37861
37993
  const cleanedStyle = { ...style };
37862
- for (const [property, defaultValue] of Object.entries(DEFAULT_STYLE)) {
37863
- if (cleanedStyle[property] === defaultValue) {
37994
+ for (const property in DEFAULT_STYLE) {
37995
+ if (cleanedStyle[property] === DEFAULT_STYLE[property]) {
37864
37996
  delete cleanedStyle[property];
37865
37997
  }
37866
37998
  }
@@ -38016,10 +38148,7 @@ class CellPlugin extends CorePlugin {
38016
38148
  else {
38017
38149
  style = before ? before.style : undefined;
38018
38150
  }
38019
- const locale = this.getters.getLocale();
38020
- let format = ("format" in after ? after.format : before && before.format) ||
38021
- detectDateFormat(afterContent, locale) ||
38022
- detectNumberFormat(afterContent);
38151
+ const format = "format" in after ? after.format : before && before.format;
38023
38152
  /* Read the following IF as:
38024
38153
  * we need to remove the cell if it is completely empty, but we can know if it completely empty if:
38025
38154
  * - the command says the new content is empty and has no border/format/style
@@ -38060,6 +38189,7 @@ class CellPlugin extends CorePlugin {
38060
38189
  }
38061
38190
  createLiteralCell(id, content, format, style) {
38062
38191
  const locale = this.getters.getLocale();
38192
+ format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
38063
38193
  if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
38064
38194
  content = toString(parseLiteral(content, locale));
38065
38195
  }
@@ -38132,6 +38262,18 @@ class CellPlugin extends CorePlugin {
38132
38262
  }
38133
38263
  return "Success" /* CommandResult.Success */;
38134
38264
  }
38265
+ checkUselessUpdateCell(cmd) {
38266
+ const cell = this.getters.getCell(cmd);
38267
+ const hasContent = "content" in cmd || "formula" in cmd;
38268
+ const hasStyle = "style" in cmd;
38269
+ const hasFormat = "format" in cmd;
38270
+ if ((!hasContent || cell?.content === cmd.content) &&
38271
+ (!hasStyle || deepEquals(cell?.style, cmd.style)) &&
38272
+ (!hasFormat || cell?.format === cmd.format)) {
38273
+ return "NoChanges" /* CommandResult.NoChanges */;
38274
+ }
38275
+ return "Success" /* CommandResult.Success */;
38276
+ }
38135
38277
  }
38136
38278
  class FormulaCellWithDependencies {
38137
38279
  id;
@@ -42947,7 +43089,15 @@ class SpreadsheetRTree {
42947
43089
  if (!this.rTrees[sheetId]) {
42948
43090
  return;
42949
43091
  }
42950
- this.rTrees[sheetId].remove(item, deepEquals);
43092
+ this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
43093
+ }
43094
+ rtreeItemComparer(left, right) {
43095
+ return (left.data == right.data &&
43096
+ left.boundingBox.sheetId === right.boundingBox.sheetId &&
43097
+ left.boundingBox?.zone.left === right.boundingBox.zone.left &&
43098
+ left.boundingBox?.zone.top === right.boundingBox.zone.top &&
43099
+ left.boundingBox?.zone.right === right.boundingBox.zone.right &&
43100
+ left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
42951
43101
  }
42952
43102
  }
42953
43103
  /**
@@ -43025,7 +43175,7 @@ class FormulaDependencyGraph {
43025
43175
  const queue = Array.from(ranges).reverse();
43026
43176
  while (queue.length > 0) {
43027
43177
  const range = queue.pop();
43028
- visited.add(...this.encoder.encodeBoundingBox(range));
43178
+ visited.addMany(this.encoder.encodeBoundingBox(range));
43029
43179
  const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
43030
43180
  for (const positionId of impactedPositionIds) {
43031
43181
  if (!visited.has(positionId)) {
@@ -43033,7 +43183,7 @@ class FormulaDependencyGraph {
43033
43183
  }
43034
43184
  }
43035
43185
  }
43036
- visited.delete(...ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
43186
+ visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
43037
43187
  return visited;
43038
43188
  }
43039
43189
  }
@@ -43119,6 +43269,7 @@ const EMPTY_ARRAY = [];
43119
43269
  const MAX_ITERATION = 30;
43120
43270
  const ERROR_CYCLE_CELL = createEvaluatedCell(new CircularDependencyError());
43121
43271
  const EMPTY_CELL = createEvaluatedCell({ value: null });
43272
+ const EVAL_CONTEXT_INDEX = 2;
43122
43273
  class Evaluator {
43123
43274
  context;
43124
43275
  getters;
@@ -43164,17 +43315,24 @@ class Evaluator {
43164
43315
  const dependencies = this.getDirectDependencies(positionId);
43165
43316
  this.formulaDependencies().addDependencies(positionId, dependencies);
43166
43317
  }
43318
+ addDependencies(position, dependencies) {
43319
+ const positionId = this.encoder.encode(position);
43320
+ this.formulaDependencies().addDependencies(positionId, dependencies);
43321
+ }
43167
43322
  updateCompilationParameters() {
43168
43323
  // rebuild the compilation parameters (with a clean cache)
43169
43324
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
43325
+ this.compilationParams[EVAL_CONTEXT_INDEX].updateDependencies =
43326
+ this.updateDependencies.bind(this);
43327
+ this.compilationParams[EVAL_CONTEXT_INDEX].addDependencies = this.addDependencies.bind(this);
43170
43328
  }
43171
43329
  evaluateCells(positions) {
43172
43330
  const cells = positions.map((p) => this.encoder.encode(p));
43173
43331
  const cellsToCompute = new JetSet(cells);
43174
43332
  const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
43175
- cellsToCompute.add(...this.getCellsDependingOn(cells));
43176
- cellsToCompute.add(...arrayFormulasPositionIds);
43177
- cellsToCompute.add(...this.getCellsDependingOn(arrayFormulasPositionIds));
43333
+ cellsToCompute.addMany(this.getCellsDependingOn(cells));
43334
+ cellsToCompute.addMany(arrayFormulasPositionIds);
43335
+ cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
43178
43336
  this.evaluate(cellsToCompute);
43179
43337
  }
43180
43338
  getArrayFormulasImpactedByChangesOf(positionIds) {
@@ -43188,7 +43346,7 @@ class Evaluator {
43188
43346
  }
43189
43347
  if (!content) {
43190
43348
  // The previous content could have blocked some array formulas
43191
- impactedPositionIds.add(...this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
43349
+ impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
43192
43350
  }
43193
43351
  }
43194
43352
  return impactedPositionIds;
@@ -43240,7 +43398,7 @@ class Evaluator {
43240
43398
  }
43241
43399
  const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
43242
43400
  const cells = new JetSet(arrayFormulas);
43243
- cells.add(...this.getCellsDependingOn(arrayFormulas));
43401
+ cells.addMany(this.getCellsDependingOn(arrayFormulas));
43244
43402
  return cells;
43245
43403
  }
43246
43404
  nextPositionsToUpdate = new JetSet();
@@ -43368,7 +43526,7 @@ class Evaluator {
43368
43526
  this.setEvaluatedCell(positionId, evaluatedCell);
43369
43527
  // check if formula dependencies present in the spread zone
43370
43528
  // if so, they need to be recomputed
43371
- this.nextPositionsToUpdate.add(...this.getCellsDependingOn([positionId]));
43529
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
43372
43530
  };
43373
43531
  }
43374
43532
  invalidateSpreading(positionId) {
@@ -43383,8 +43541,8 @@ class Evaluator {
43383
43541
  continue;
43384
43542
  }
43385
43543
  this.evaluatedCells.delete(child);
43386
- this.nextPositionsToUpdate.add(...this.getCellsDependingOn([child]));
43387
- this.nextPositionsToUpdate.add(...this.getArrayFormulasBlockedByOrSpreadingOn(child));
43544
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
43545
+ this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
43388
43546
  }
43389
43547
  this.spreadingRelations.removeNode(positionId);
43390
43548
  }
@@ -43513,15 +43671,15 @@ class PositionBitsEncoder {
43513
43671
  }
43514
43672
  }
43515
43673
  function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId, cellId) {
43516
- compilationParams[2].__originCellXC = lazy(() => {
43674
+ compilationParams[EVAL_CONTEXT_INDEX].__originCellXC = lazy(() => {
43517
43675
  if (!cellId) {
43518
43676
  return undefined;
43519
43677
  }
43520
43678
  // compute the value lazily for performance reasons
43521
- const position = compilationParams[2].getters.getCellPosition(cellId);
43679
+ const position = compilationParams[EVAL_CONTEXT_INDEX].getters.getCellPosition(cellId);
43522
43680
  return toXC(position.col, position.row);
43523
43681
  });
43524
- compilationParams[2].__originSheetId = sheetId;
43682
+ compilationParams[EVAL_CONTEXT_INDEX].__originSheetId = sheetId;
43525
43683
  return compiledFormula.execute(compiledFormula.dependencies, ...compilationParams);
43526
43684
  }
43527
43685
 
@@ -43851,8 +44009,13 @@ function colorDistance(color1, color2) {
43851
44009
  */
43852
44010
  class CustomColorsPlugin extends UIPlugin {
43853
44011
  customColors = {};
44012
+ configCustomColors;
43854
44013
  shouldUpdateColors = false;
43855
44014
  static getters = ["getCustomColors"];
44015
+ constructor(config) {
44016
+ super(config);
44017
+ this.configCustomColors = config.customColors;
44018
+ }
43856
44019
  handle(cmd) {
43857
44020
  switch (cmd.type) {
43858
44021
  case "UPDATE_CELL":
@@ -43874,7 +44037,7 @@ class CustomColorsPlugin extends UIPlugin {
43874
44037
  }
43875
44038
  }
43876
44039
  getCustomColors() {
43877
- let usedColors = [];
44040
+ let usedColors = this.configCustomColors;
43878
44041
  for (const sheetId of this.getters.getSheetIds()) {
43879
44042
  usedColors = usedColors.concat(this.getColorsFromCells(sheetId), this.getFormattingColors(sheetId), this.getChartColors(sheetId));
43880
44043
  }
@@ -46847,7 +47010,7 @@ class SheetUIPlugin extends UIPlugin {
46847
47010
  "getCellText",
46848
47011
  "getCellMultiLineText",
46849
47012
  "getContiguousZone",
46850
- "isCellEmpty",
47013
+ "isEvaluatedCellEmpty",
46851
47014
  ];
46852
47015
  ctx = document.createElement("canvas").getContext("2d");
46853
47016
  // ---------------------------------------------------------------------------
@@ -46975,14 +47138,26 @@ class SheetUIPlugin extends UIPlugin {
46975
47138
  return zone;
46976
47139
  }
46977
47140
  /**
46978
- * Check if a cell is empty. If the cell is part of a merge,
46979
- * check if the merge containing the cell is empty.
47141
+ * Checks if a cell evaluated value is empty. If the cell is part of a merge,
47142
+ * the check applies to the main cell of the merge.
46980
47143
  */
46981
- isCellEmpty(position) {
47144
+ //TODORAR this does not fit the new scheme where a cell with an empty string is not empty anymore
47145
+ // this means the navigation was acually altered with the recent change
47146
+ // remove the getter and put it back in selection processor as nobody uses it
47147
+ isEvaluatedCellEmpty(position) {
46982
47148
  const mainPosition = this.getters.getMainCellPosition(position);
46983
47149
  const cell = this.getters.getEvaluatedCell(mainPosition);
46984
47150
  return cell.type === CellValueType.empty;
46985
47151
  }
47152
+ /**
47153
+ * Checks if a cell is empty (i.e. does not have a content or a formula does not spread over it).
47154
+ * If the cell is part of a merge, the check applies to the main cell of the merge.
47155
+ */
47156
+ isCellEmpty(position) {
47157
+ const mainPosition = this.getters.getMainCellPosition(position);
47158
+ return !(this.getters.getCorrespondingFormulaCell(mainPosition) ||
47159
+ this.getters.getCell(mainPosition)?.content);
47160
+ }
46986
47161
  getColMaxWidth(sheetId, index) {
46987
47162
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
46988
47163
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
@@ -51517,7 +51692,7 @@ class FindAndReplacePanel extends owl.Component {
51517
51692
  if (ev.key === "Enter") {
51518
51693
  ev.preventDefault();
51519
51694
  ev.stopPropagation();
51520
- this.store.selectNextMatch();
51695
+ ev.shiftKey ? this.store.selectPreviousMatch() : this.store.selectNextMatch();
51521
51696
  }
51522
51697
  }
51523
51698
  onKeydownReplace(ev) {
@@ -53213,22 +53388,20 @@ css /* scss */ `
53213
53388
  `;
53214
53389
  class SidePanel extends owl.Component {
53215
53390
  static template = "o-spreadsheet-SidePanel";
53216
- static props = {
53217
- component: String,
53218
- panelProps: { type: Object, optional: true },
53219
- onCloseSidePanel: Function,
53220
- };
53221
- state;
53391
+ static props = {};
53392
+ sidePanelStore;
53222
53393
  setup() {
53223
- this.state = owl.useState({
53224
- panel: sidePanelRegistry.get(this.props.component),
53225
- });
53226
- owl.onWillUpdateProps((nextProps) => (this.state.panel = sidePanelRegistry.get(nextProps.component)));
53394
+ this.sidePanelStore = useStore(SidePanelStore);
53395
+ }
53396
+ get panel() {
53397
+ return sidePanelRegistry.get(this.sidePanelStore.componentTag);
53398
+ }
53399
+ close() {
53400
+ this.sidePanelStore.close();
53227
53401
  }
53228
53402
  getTitle() {
53229
- return typeof this.state.panel.title === "function"
53230
- ? this.state.panel.title(this.env)
53231
- : this.state.panel.title;
53403
+ const panel = this.panel;
53404
+ return typeof panel.title === "function" ? panel.title(this.env) : panel.title;
53232
53405
  }
53233
53406
  }
53234
53407
 
@@ -54162,10 +54335,13 @@ class Spreadsheet extends owl.Component {
54162
54335
  }
54163
54336
  setup() {
54164
54337
  const stores = useStoreProvider();
54165
- this.sidePanel = owl.useState({ isOpen: false, panelProps: {} });
54338
+ stores.inject(ModelStore, this.model);
54339
+ this.notificationStore = useStore(NotificationStore);
54340
+ this.composerFocusStore = useStore(ComposerFocusStore);
54341
+ this.sidePanel = useStore(SidePanelStore);
54166
54342
  this.keyDownMapping = {
54167
- "CTRL+H": () => this.toggleSidePanel("FindAndReplace", {}),
54168
- "CTRL+F": () => this.toggleSidePanel("FindAndReplace", {}),
54343
+ "CTRL+H": () => this.sidePanel.toggle("FindAndReplace", {}),
54344
+ "CTRL+F": () => this.sidePanel.toggle("FindAndReplace", {}),
54169
54345
  };
54170
54346
  const fileStore = this.model.config.external.fileStore;
54171
54347
  owl.useSubEnv({
@@ -54174,11 +54350,10 @@ class Spreadsheet extends owl.Component {
54174
54350
  loadCurrencies: this.model.config.external.loadCurrencies,
54175
54351
  loadLocales: this.model.config.external.loadLocales,
54176
54352
  isDashboard: () => this.model.getters.isDashboard(),
54177
- openSidePanel: this.openSidePanel.bind(this),
54178
- toggleSidePanel: this.toggleSidePanel.bind(this),
54353
+ openSidePanel: this.sidePanel.open.bind(this.sidePanel),
54354
+ toggleSidePanel: this.sidePanel.toggle.bind(this.sidePanel),
54179
54355
  clipboard: this.env.clipboard || instantiateClipboard(),
54180
54356
  startCellEdition: (content) => this.composerFocusStore.focusGridComposerCell(content),
54181
- //TODORAR: make a store out of this
54182
54357
  });
54183
54358
  owl.useEffect(() => {
54184
54359
  /**
@@ -54207,9 +54382,6 @@ class Spreadsheet extends owl.Component {
54207
54382
  owl.onPatched(() => {
54208
54383
  this.checkViewportSize();
54209
54384
  });
54210
- stores.inject(ModelStore, this.model);
54211
- this.notificationStore = useStore(NotificationStore);
54212
- this.composerFocusStore = useStore(ComposerFocusStore);
54213
54385
  }
54214
54386
  bindModelEvents() {
54215
54387
  this.model.on("update", this, () => this.render(true));
@@ -54242,28 +54414,6 @@ class Spreadsheet extends owl.Component {
54242
54414
  this.isViewportTooSmall = false;
54243
54415
  }
54244
54416
  }
54245
- openSidePanel(panel, panelProps) {
54246
- if (this.sidePanel.isOpen && panel !== this.sidePanel.component) {
54247
- this.sidePanel.panelProps?.onCloseSidePanel?.();
54248
- }
54249
- this.sidePanel.component = panel;
54250
- this.sidePanel.panelProps = panelProps;
54251
- this.sidePanel.isOpen = true;
54252
- }
54253
- closeSidePanel() {
54254
- this.sidePanel.isOpen = false;
54255
- this.focusGrid();
54256
- this.sidePanel.panelProps?.onCloseSidePanel?.();
54257
- }
54258
- toggleSidePanel(panel, panelProps) {
54259
- if (this.sidePanel.isOpen && panel === this.sidePanel.component) {
54260
- this.sidePanel.isOpen = false;
54261
- this.focusGrid();
54262
- }
54263
- else {
54264
- this.openSidePanel(panel, panelProps);
54265
- }
54266
- }
54267
54417
  focusGrid() {
54268
54418
  if (!this._focusGrid) {
54269
54419
  return;
@@ -55692,8 +55842,8 @@ class SelectionStreamProcessorImpl {
55692
55842
  let currentPosition = startPosition;
55693
55843
  // If both the current cell and the next cell are not empty, we want to go to the end of the cluster
55694
55844
  const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
55695
- let mode = !this.getters.isCellEmpty({ ...currentPosition, sheetId }) &&
55696
- !this.getters.isCellEmpty({ ...nextCellPosition, sheetId })
55845
+ let mode = !this.isCellSkippableInCluster({ ...currentPosition, sheetId }) &&
55846
+ !this.isCellSkippableInCluster({ ...nextCellPosition, sheetId })
55697
55847
  ? "endOfCluster"
55698
55848
  : "nextCluster";
55699
55849
  while (true) {
@@ -55703,7 +55853,7 @@ class SelectionStreamProcessorImpl {
55703
55853
  currentPosition.row === nextCellPosition.row) {
55704
55854
  break;
55705
55855
  }
55706
- const isNextCellEmpty = this.getters.isCellEmpty({ ...nextCellPosition, sheetId });
55856
+ const isNextCellEmpty = this.isCellSkippableInCluster({ ...nextCellPosition, sheetId });
55707
55857
  if (mode === "endOfCluster" && isNextCellEmpty) {
55708
55858
  break;
55709
55859
  }
@@ -55734,6 +55884,11 @@ class SelectionStreamProcessorImpl {
55734
55884
  getPosition() {
55735
55885
  return { ...this.anchor.cell };
55736
55886
  }
55887
+ isCellSkippableInCluster(position) {
55888
+ const mainPosition = this.getters.getMainCellPosition(position);
55889
+ const cell = this.getters.getEvaluatedCell(mainPosition);
55890
+ return (cell.type === CellValueType.empty || (cell.type === CellValueType.text && cell.value === ""));
55891
+ }
55737
55892
  }
55738
55893
 
55739
55894
  class StateObserver {
@@ -57600,6 +57755,7 @@ class Model extends EventBus {
57600
57755
  snapshotRequested: false,
57601
57756
  notifyUI: (payload) => this.trigger("notify-ui", payload),
57602
57757
  raiseBlockingErrorUI: (text) => this.trigger("raise-error-ui", { text }),
57758
+ customColors: config.customColors || [],
57603
57759
  };
57604
57760
  }
57605
57761
  setupExternalConfig(external) {
@@ -57631,6 +57787,7 @@ class Model extends EventBus {
57631
57787
  uiActions: this.config,
57632
57788
  session: this.session,
57633
57789
  defaultCurrencyFormat: this.config.defaultCurrencyFormat,
57790
+ customColors: this.config.customColors || [],
57634
57791
  };
57635
57792
  }
57636
57793
  // ---------------------------------------------------------------------------
@@ -57930,6 +58087,10 @@ const helpers = {
57930
58087
  deepEquals,
57931
58088
  overlap,
57932
58089
  union,
58090
+ isInside,
58091
+ deepCopy,
58092
+ expandZoneOnInsertion,
58093
+ reduceZoneOnDeletion,
57933
58094
  };
57934
58095
  const links = {
57935
58096
  isMarkdownLink,
@@ -57984,6 +58145,9 @@ const stores = {
57984
58145
  RendererStore,
57985
58146
  SelectionInputStore,
57986
58147
  SpreadsheetStore,
58148
+ useStore,
58149
+ useLocalStore,
58150
+ SidePanelStore,
57987
58151
  };
57988
58152
  function addFunction(functionName, functionDescription) {
57989
58153
  functionRegistry.add(functionName, functionDescription);
@@ -57996,7 +58160,9 @@ const constants = {
57996
58160
  SECONDARY_COLOR,
57997
58161
  };
57998
58162
 
58163
+ exports.AbstractCellClipboardHandler = AbstractCellClipboardHandler;
57999
58164
  exports.AbstractChart = AbstractChart;
58165
+ exports.AbstractFigureClipboardHandler = AbstractFigureClipboardHandler;
58000
58166
  exports.CellErrorType = CellErrorType;
58001
58167
  exports.CorePlugin = CorePlugin;
58002
58168
  exports.DispatchResult = DispatchResult;
@@ -58036,6 +58202,6 @@ exports.stores = stores;
58036
58202
  exports.tokenize = tokenize;
58037
58203
 
58038
58204
 
58039
- __info__.version = "17.2.0-alpha.4";
58040
- __info__.date = "2024-02-09T13:10:23.460Z";
58041
- __info__.hash = "1b33cf4";
58205
+ __info__.version = "17.2.0-alpha.5";
58206
+ __info__.date = "2024-02-16T14:27:52.323Z";
58207
+ __info__.hash = "0c69dd8";