@odoo/o-spreadsheet 16.0.5 → 16.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -111,88 +111,88 @@ const LINK_COLOR = "#01666b";
111
111
  const FILTERS_COLOR = "#188038";
112
112
  const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
113
113
  const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
114
- // Color picker
114
+ // Color picker defaults as upper case HEX to match `toHex`helper
115
115
  const COLOR_PICKER_DEFAULTS = [
116
116
  "#000000",
117
117
  "#434343",
118
118
  "#666666",
119
119
  "#999999",
120
- "#b7b7b7",
121
- "#cccccc",
122
- "#d9d9d9",
123
- "#efefef",
124
- "#f3f3f3",
125
- "#ffffff",
120
+ "#B7B7B7",
121
+ "#CCCCCC",
122
+ "#D9D9D9",
123
+ "#EFEFEF",
124
+ "#F3F3F3",
125
+ "#FFFFFF",
126
126
  "#980000",
127
- "#ff0000",
128
- "#ff9900",
129
- "#ffff00",
130
- "#00ff00",
131
- "#00ffff",
132
- "#4a86e8",
133
- "#0000ff",
134
- "#9900ff",
135
- "#ff00ff",
136
- "#e6b8af",
137
- "#f4cccc",
138
- "#fce5cd",
139
- "#fff2cc",
140
- "#d9ead3",
141
- "#d0e0e3",
142
- "#c9daf8",
143
- "#cfe2f3",
144
- "#d9d2e9",
145
- "#ead1dc",
146
- "#dd7e6b",
147
- "#ea9999",
148
- "#f9cb9c",
149
- "#ffe599",
150
- "#b6d7a8",
151
- "#a2c4c9",
152
- "#a4c2f4",
153
- "#9fc5e8",
154
- "#b4a7d6",
155
- "#d5a6bd",
156
- "#cc4125",
157
- "#e06666",
158
- "#f6b26b",
159
- "#ffd966",
160
- "#93c47d",
161
- "#76a5af",
162
- "#6d9eeb",
163
- "#6fa8dc",
164
- "#8e7cc3",
165
- "#c27ba0",
166
- "#a61c00",
167
- "#cc0000",
168
- "#e69138",
169
- "#f1c232",
170
- "#6aa84f",
171
- "#45818e",
172
- "#3c78d8",
173
- "#3d85c6",
174
- "#674ea7",
175
- "#a64d79",
176
- "#85200c",
127
+ "#FF0000",
128
+ "#FF9900",
129
+ "#FFFF00",
130
+ "#00FF00",
131
+ "#00FFFF",
132
+ "#4A86E8",
133
+ "#0000FF",
134
+ "#9900FF",
135
+ "#FF00FF",
136
+ "#E6B8AF",
137
+ "#F4CCCC",
138
+ "#FCE5CD",
139
+ "#FFF2CC",
140
+ "#D9EAD3",
141
+ "#D0E0E3",
142
+ "#C9DAF8",
143
+ "#CFE2F3",
144
+ "#D9D2E9",
145
+ "#EAD1DC",
146
+ "#DD7E6B",
147
+ "#EA9999",
148
+ "#F9CB9C",
149
+ "#FFE599",
150
+ "#B6D7A8",
151
+ "#A2C4C9",
152
+ "#A4C2F4",
153
+ "#9FC5E8",
154
+ "#B4A7D6",
155
+ "#D5A6BD",
156
+ "#CC4125",
157
+ "#E06666",
158
+ "#F6B26B",
159
+ "#FFD966",
160
+ "#93C47D",
161
+ "#76A5AF",
162
+ "#6D9EEB",
163
+ "#6FA8DC",
164
+ "#8E7CC3",
165
+ "#C27BA0",
166
+ "#A61C00",
167
+ "#CC0000",
168
+ "#E69138",
169
+ "#F1C232",
170
+ "#6AA84F",
171
+ "#45818E",
172
+ "#3C78D8",
173
+ "#3D85C6",
174
+ "#674EA7",
175
+ "#A64D79",
176
+ "#85200C",
177
177
  "#990000",
178
- "#b45f06",
179
- "#bf9000",
180
- "#38761d",
181
- "#134f5c",
182
- "#1155cc",
183
- "#0b5394",
184
- "#351c75",
185
- "#741b47",
186
- "#5b0f00",
178
+ "#B45F06",
179
+ "#BF9000",
180
+ "#38761D",
181
+ "#134F5C",
182
+ "#1155CC",
183
+ "#0B5394",
184
+ "#351C75",
185
+ "#741B47",
186
+ "#5B0F00",
187
187
  "#660000",
188
- "#783f04",
189
- "#7f6000",
190
- "#274e13",
191
- "#0c343d",
192
- "#1c4587",
188
+ "#783F04",
189
+ "#7F6000",
190
+ "#274E13",
191
+ "#0C343D",
192
+ "#1C4587",
193
193
  "#073763",
194
- "#20124d",
195
- "#4c1130",
194
+ "#20124D",
195
+ "#4C1130",
196
196
  ];
197
197
  // Dimensions
198
198
  const MIN_ROW_HEIGHT = 10;
@@ -230,7 +230,7 @@ const DEFAULT_FONT = "'Roboto', arial";
230
230
  const DEFAULT_BORDER_DESC = ["thin", "#000"];
231
231
  const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
232
232
  // DateTimeRegex
233
- const DATETIME_FORMAT = /[ymd:]/;
233
+ const DATETIME_FORMAT = /[ymdhs:]/;
234
234
  // Ranges
235
235
  const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
236
236
  // Max Number of history steps kept in memory
@@ -266,11 +266,13 @@ var ComponentsImportance;
266
266
  ComponentsImportance[ComponentsImportance["Highlight"] = 5] = "Highlight";
267
267
  ComponentsImportance[ComponentsImportance["Figure"] = 10] = "Figure";
268
268
  ComponentsImportance[ComponentsImportance["ScrollBar"] = 15] = "ScrollBar";
269
- ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
270
- ComponentsImportance[ComponentsImportance["Composer"] = 20] = "Composer";
269
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
270
+ ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
271
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
271
272
  ComponentsImportance[ComponentsImportance["ColorPicker"] = 25] = "ColorPicker";
272
273
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
273
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
274
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
275
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
274
276
  ComponentsImportance[ComponentsImportance["ChartAnchor"] = 1000] = "ChartAnchor";
275
277
  })(ComponentsImportance || (ComponentsImportance = {}));
276
278
  const DEFAULT_SHEETVIEW_SIZE = 1000;
@@ -1039,6 +1041,8 @@ function transpose2dArray(matrix) {
1039
1041
  return matrix[0].map((_, i) => matrix.map((row) => row[i]));
1040
1042
  }
1041
1043
 
1044
+ const RBA_REGEX = /rgba?\(|\s+|\)/gi;
1045
+ const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
1042
1046
  const colors$1 = [
1043
1047
  "#eb6d00",
1044
1048
  "#0074d9",
@@ -1069,7 +1073,10 @@ function getNextColor() {
1069
1073
  }
1070
1074
  /**
1071
1075
  * Converts any CSS color value to a standardized hex6 value.
1072
- * Accepts: hex3, hex6, hex8 and rgb (rgba is not supported)
1076
+ * Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
1077
+ *
1078
+ * [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
1079
+ * with r,g,b ∈ [0, 255] and a ∈ [0, 1]
1073
1080
  *
1074
1081
  * toHex("#ABC")
1075
1082
  * >> "#AABBCC"
@@ -1080,27 +1087,31 @@ function getNextColor() {
1080
1087
  * toHex("rgb(30, 80, 16)")
1081
1088
  * >> "#1E5010"
1082
1089
  *
1090
+ * * toHex("rgb(30, 80, 16, 0.5)")
1091
+ * >> "#1E501080"
1092
+ *
1083
1093
  */
1084
1094
  function toHex(color) {
1085
- if (color.includes("rgba")) {
1086
- throw new Error(`rgba() conversion currently not supported: ${color}`);
1095
+ let hexColor = color;
1096
+ if (color.startsWith("rgb")) {
1097
+ hexColor = rgbaStringToHex(color);
1087
1098
  }
1088
- if (color.includes("rgb")) {
1089
- return rgbToHex6(color);
1099
+ else {
1100
+ hexColor = color.replace("#", "").toUpperCase();
1101
+ if (hexColor.length === 3 || hexColor.length === 4) {
1102
+ hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
1103
+ }
1104
+ hexColor = `#${hexColor}`;
1090
1105
  }
1091
- color = color.replace("#", "").toUpperCase();
1092
- if (color.length === 3 || color.length === 4) {
1093
- color = color.split("").reduce((acc, h) => acc + h + h, "");
1106
+ if (!hexColor.match(HEX_MATCH)) {
1107
+ throw new Error(`invalid color input: ${color}`);
1094
1108
  }
1095
- if (color.replace(/[a-f0-9]/gi, "") !== "") {
1096
- throw new Error("invalid color");
1097
- }
1098
- return "#" + color;
1109
+ return hexColor;
1099
1110
  }
1100
1111
  function isColorValid(color) {
1101
1112
  try {
1102
- const { r, g, b, a } = colorToRGBA(color);
1103
- return (isColorValueValid(r) && isColorValueValid(g) && isColorValueValid(b) && isColorValueValid(a));
1113
+ toHex(color);
1114
+ return true;
1104
1115
  }
1105
1116
  catch (error) {
1106
1117
  return false;
@@ -1133,15 +1144,29 @@ function relativeLuminance(color) {
1133
1144
  /**
1134
1145
  * Convert a CSS rgb color string to a standardized hex6 color value.
1135
1146
  *
1136
- * rgbToHex6("rgb(30, 80, 16)")
1147
+ * rgbaStringToHex("rgb(30, 80, 16)")
1137
1148
  * >> "#1E5010"
1149
+ *
1150
+ * rgbaStringToHex("rgba(30, 80, 16, 0.5)")
1151
+ * >> "#1E501080"
1152
+ *
1153
+ * DOES NOT SUPPORT NON INTEGER RGB VALUES
1138
1154
  */
1139
- function rgbToHex6(color) {
1140
- return ("#" +
1141
- concat(color
1142
- .slice(4, -1)
1143
- .split(",")
1144
- .map((valueString) => parseInt(valueString, 10).toString(16).padStart(2, "0"))).toUpperCase());
1155
+ function rgbaStringToHex(color) {
1156
+ const stringVals = color.replace(RBA_REGEX, "").split(",");
1157
+ let alphaHex = 255;
1158
+ if (stringVals.length !== 3 && stringVals.length !== 4) {
1159
+ throw new Error("invalid color");
1160
+ }
1161
+ else if (stringVals.length === 4) {
1162
+ const alpha = parseFloat(stringVals.pop() || "1");
1163
+ alphaHex = Math.round((alpha || 1) * 255);
1164
+ }
1165
+ const vals = stringVals.map((val) => parseInt(val, 10));
1166
+ if (alphaHex !== 255) {
1167
+ vals.push(alphaHex);
1168
+ }
1169
+ return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
1145
1170
  }
1146
1171
  /**
1147
1172
  * RGBA to HEX representation (#RRGGBBAA).
@@ -1163,7 +1188,7 @@ function rgbaToHex(rgba) {
1163
1188
  a = "0" + a;
1164
1189
  if (a === "ff")
1165
1190
  a = "";
1166
- return "#" + r + g + b + a;
1191
+ return ("#" + r + g + b + a).toUpperCase();
1167
1192
  }
1168
1193
  /**
1169
1194
  * Color string to RGBA representation
@@ -1284,6 +1309,9 @@ function rgbaToHSLA(rgba) {
1284
1309
  s = +(s * 100).toFixed(1);
1285
1310
  l = +(l * 100).toFixed(1);
1286
1311
  return { a: rgba.a, h, s, l };
1312
+ }
1313
+ function isSameColor(color1, color2) {
1314
+ return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
1287
1315
  }
1288
1316
 
1289
1317
  /** Reference of a cell (eg. A1, $B$5) */
@@ -1842,7 +1870,7 @@ function convertInternalFormatToFormat(internalFormat) {
1842
1870
  * formula, commas are used to separate arguments
1843
1871
  * - it does not support % symbol, in formulas % is an operator
1844
1872
  */
1845
- const formulaNumberRegexp = /^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+/;
1873
+ const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
1846
1874
  const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
1847
1875
  const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
1848
1876
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -3822,7 +3850,7 @@ class Popover extends Component {
3822
3850
  const shadow = maxHeight !== 0 ? "box-shadow: 1px 2px 5px 2px rgb(51 51 51 / 15%);" : "";
3823
3851
  return `
3824
3852
  position: absolute;
3825
- z-index: ${ComponentsImportance.Popover};
3853
+ z-index: ${this.props.zIndex};
3826
3854
  ${verticalPosition}px;
3827
3855
  ${horizontalPosition}px;
3828
3856
  ${height}px;
@@ -3866,6 +3894,7 @@ Popover.defaultProps = {
3866
3894
  verticalOffset: 0,
3867
3895
  marginTop: 0,
3868
3896
  onMouseWheel: () => { },
3897
+ zIndex: ComponentsImportance.Popover,
3869
3898
  };
3870
3899
 
3871
3900
  //------------------------------------------------------------------------------
@@ -8428,6 +8457,9 @@ class ColorPicker extends Component {
8428
8457
  const { display, background, left, top } = this.state.style;
8429
8458
  return `display:${display};${display === "block" ? `background-color:${background};left:${left};top:${top};` : ""}`;
8430
8459
  }
8460
+ isSameColor(color1, color2) {
8461
+ return isSameColor(color1, color2);
8462
+ }
8431
8463
  }
8432
8464
  ColorPicker.template = "o-spreadsheet-ColorPicker";
8433
8465
 
@@ -8553,6 +8585,12 @@ class GaugeChartDesignPanel extends Component {
8553
8585
  const cancelledReasons = [...(((_a = this.state.sectionRuleDispatchResult) === null || _a === void 0 ? void 0 : _a.reasons) || [])];
8554
8586
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
8555
8587
  }
8588
+ onClick(ev) {
8589
+ this.state.openedMenu = undefined;
8590
+ }
8591
+ setup() {
8592
+ useExternalListener(window, "click", this.onClick);
8593
+ }
8556
8594
  updateBackgroundColor(color) {
8557
8595
  this.state.openedMenu = undefined;
8558
8596
  this.props.updateChart({
@@ -8721,6 +8759,12 @@ class ScorecardChartDesignPanel extends Component {
8721
8759
  openedColorPicker: undefined,
8722
8760
  });
8723
8761
  }
8762
+ onClick(ev) {
8763
+ this.state.openedColorPicker = undefined;
8764
+ }
8765
+ setup() {
8766
+ useExternalListener(window, "click", this.onClick);
8767
+ }
8724
8768
  updateTitle(ev) {
8725
8769
  this.props.updateChart({
8726
8770
  title: ev.target.value,
@@ -19922,7 +19966,6 @@ css /* scss */ `
19922
19966
  padding: 0;
19923
19967
  margin: 0;
19924
19968
  border: 0;
19925
- z-index: ${ComponentsImportance.Composer};
19926
19969
  flex-grow: 1;
19927
19970
  max-height: inherit;
19928
19971
  .o-composer {
@@ -19956,6 +19999,10 @@ css /* scss */ `
19956
19999
  .o-topbar-toolbar .o-composer-container:focus-within {
19957
20000
  border: 1px solid ${SELECTION_BORDER_COLOR};
19958
20001
  }
20002
+
20003
+ .o-topbar-toolbar .o-composer-container {
20004
+ z-index: ${ComponentsImportance.TopBarComposer};
20005
+ }
19959
20006
  `;
19960
20007
  class Composer extends Component {
19961
20008
  constructor() {
@@ -20380,7 +20427,7 @@ const SCROLLBAR_HIGHT = 15;
20380
20427
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
20381
20428
  css /* scss */ `
20382
20429
  div.o-grid-composer {
20383
- z-index: ${ComponentsImportance.Composer};
20430
+ z-index: ${ComponentsImportance.GridComposer};
20384
20431
  box-sizing: border-box;
20385
20432
  position: absolute;
20386
20433
  border: ${COMPOSER_BORDER_WIDTH}px solid ${SELECTION_BORDER_COLOR};
@@ -21210,6 +21257,10 @@ GridOverlay.defaultProps = {
21210
21257
  };
21211
21258
 
21212
21259
  class GridPopover extends Component {
21260
+ constructor() {
21261
+ super(...arguments);
21262
+ this.zIndex = ComponentsImportance.GridPopover;
21263
+ }
21213
21264
  get cellPopover() {
21214
21265
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
21215
21266
  if (!popover.isOpen) {
@@ -23732,6 +23783,72 @@ function fixXlsxUnicode(str) {
23732
23783
  });
23733
23784
  }
23734
23785
 
23786
+ const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
23787
+ /**
23788
+ * Convert excel format to o_spreadsheet format
23789
+ *
23790
+ * Excel format are defined in openXML §18.8.31
23791
+ */
23792
+ function convertXlsxFormat(numFmtId, formats, warningManager) {
23793
+ var _a, _b, _c;
23794
+ if (numFmtId === 0) {
23795
+ return undefined;
23796
+ }
23797
+ // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23798
+ let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23799
+ if (format) {
23800
+ try {
23801
+ let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23802
+ convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23803
+ convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23804
+ // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23805
+ const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23806
+ const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23807
+ if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23808
+ throw new Error("Multiple escaped blocks in format");
23809
+ }
23810
+ convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23811
+ convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
23812
+ convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23813
+ convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23814
+ convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
23815
+ if (isXlsxDateFormat(convertedFormat)) {
23816
+ convertedFormat = convertDateFormat$1(convertedFormat);
23817
+ }
23818
+ if (isFormatSupported(convertedFormat)) {
23819
+ return convertedFormat;
23820
+ }
23821
+ }
23822
+ catch (e) { }
23823
+ }
23824
+ warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23825
+ return undefined;
23826
+ }
23827
+ function isFormatSupported(format) {
23828
+ try {
23829
+ formatValue(0, format);
23830
+ return true;
23831
+ }
23832
+ catch (e) {
23833
+ return false;
23834
+ }
23835
+ }
23836
+ function isXlsxDateFormat(format) {
23837
+ return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
23838
+ }
23839
+ function convertDateFormat$1(format) {
23840
+ // Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
23841
+ // but can still occur and are supported by Excel/Google sheets
23842
+ format = format.toLowerCase();
23843
+ format = format.replace(/mmmmm|mmmm|mmm/g, "mm");
23844
+ format = format.replace(/dddd|ddd/g, "dd");
23845
+ format = format.replace(/am\/pm|a\/m/g, "a");
23846
+ format = format.replace(/\byy\b/g, "yyyy");
23847
+ format = format.replace(/hhhh/g, "hh");
23848
+ format = format.replace(/\bh\b/g, "hh");
23849
+ return format;
23850
+ }
23851
+
23735
23852
  function convertBorders(data, warningManager) {
23736
23853
  const borderArray = data.borders.map((border) => {
23737
23854
  addBorderWarnings(border, warningManager);
@@ -23796,41 +23913,6 @@ function convertFormats(data, warningManager) {
23796
23913
  }
23797
23914
  return arrayToObject(formats, 1);
23798
23915
  }
23799
- /**
23800
- * Convert excel format to o_spreadsheet format
23801
- *
23802
- * Excel format are defined in openXML §18.8.31
23803
- */
23804
- function convertXlsxFormat(numFmtId, formats, warningManager) {
23805
- var _a, _b, _c;
23806
- if (numFmtId === 0) {
23807
- return undefined;
23808
- }
23809
- // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23810
- let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23811
- if (format) {
23812
- try {
23813
- let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23814
- convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23815
- convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23816
- // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23817
- const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23818
- const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23819
- if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23820
- throw new Error("Multiple escaped blocks in format");
23821
- }
23822
- convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23823
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
23824
- convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23825
- convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23826
- formatValue(0, convertedFormat);
23827
- return convertedFormat;
23828
- }
23829
- catch (e) { }
23830
- }
23831
- warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23832
- return undefined;
23833
- }
23834
23916
  /**
23835
23917
  * We currently only support only a set of font sizes, we cannot define new font sizes.
23836
23918
  * This function adapts an arbitrary font size to the closest supported font size.
@@ -32013,9 +32095,7 @@ class CustomColorsPlugin extends UIPlugin {
32013
32095
  // remove duplicates first to check validity on a reduced
32014
32096
  // set of colors, then normalize to HEX and remove duplicates
32015
32097
  // again
32016
- [...new Set([...usedColors, ...this.customColors])]
32017
- .filter(isColorValid)
32018
- .map((c) => toHex(c).toLowerCase())),
32098
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
32019
32099
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
32020
32100
  }
32021
32101
  getColorsFromCells(cells) {
@@ -32076,7 +32156,7 @@ class CustomColorsPlugin extends UIPlugin {
32076
32156
  return [...chartsColors];
32077
32157
  }
32078
32158
  tryToAddColor(color) {
32079
- const formattedColor = toHex(color).toLowerCase();
32159
+ const formattedColor = toHex(color);
32080
32160
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
32081
32161
  this.customColors.add(formattedColor);
32082
32162
  }
@@ -35817,8 +35897,8 @@ class InternalViewport {
35817
35897
  this.getters = getters;
35818
35898
  this.sheetId = sheetId;
35819
35899
  this.boundaries = boundaries;
35820
- this.width = sizeInGrid.width;
35821
- this.height = sizeInGrid.height;
35900
+ this.viewportWidth = sizeInGrid.width;
35901
+ this.viewportHeight = sizeInGrid.height;
35822
35902
  this.offsetScrollbarX = offsets.x;
35823
35903
  this.offsetScrollbarY = offsets.y;
35824
35904
  this.canScrollVertically = options.canScrollVertically;
@@ -35829,6 +35909,10 @@ class InternalViewport {
35829
35909
  this.adjustViewportOffsetY();
35830
35910
  }
35831
35911
  // PUBLIC
35912
+ /** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
35913
+ * When the viewport grid size is smaller than its client width (resp. height), it will return
35914
+ * the client width (resp. height).
35915
+ */
35832
35916
  getMaxSize() {
35833
35917
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
35834
35918
  first: this.boundaries.left,
@@ -35840,20 +35924,24 @@ class InternalViewport {
35840
35924
  });
35841
35925
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
35842
35926
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
35843
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
35927
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
35844
35928
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
35845
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
35929
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
35846
35930
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
35847
- const width = lastColEnd -
35848
- this.offsetCorrectionX +
35849
- (this.canScrollHorizontally
35850
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
35851
- : 0);
35852
- const height = lastRowEnd -
35853
- this.offsetCorrectionY +
35854
- (this.canScrollVertically
35855
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
35856
- : 0);
35931
+ let width = lastColEnd - this.offsetCorrectionX;
35932
+ if (this.canScrollHorizontally) {
35933
+ width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
35934
+ Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
35935
+ );
35936
+ width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
35937
+ }
35938
+ let height = lastRowEnd - this.offsetCorrectionY;
35939
+ if (this.canScrollVertically) {
35940
+ height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
35941
+ Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
35942
+ );
35943
+ height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
35944
+ }
35857
35945
  return { width, height };
35858
35946
  }
35859
35947
  /**
@@ -35862,7 +35950,7 @@ class InternalViewport {
35862
35950
  * It returns -1 if no column is found.
35863
35951
  */
35864
35952
  getColIndex(x, absolute = false) {
35865
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
35953
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
35866
35954
  return -1;
35867
35955
  }
35868
35956
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -35873,7 +35961,7 @@ class InternalViewport {
35873
35961
  * It returns -1 if no row is found.
35874
35962
  */
35875
35963
  getRowIndex(y, absolute = false) {
35876
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
35964
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
35877
35965
  return -1;
35878
35966
  }
35879
35967
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -35897,48 +35985,66 @@ class InternalViewport {
35897
35985
  this.adjustPositionY(row);
35898
35986
  }
35899
35987
  }
35900
- adjustPositionX(col) {
35988
+ adjustPositionX(targetCol) {
35901
35989
  const sheetId = this.sheetId;
35902
- const { start, end } = this.getters.getColDimensions(sheetId, col);
35903
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
35904
- this.offsetX + this.offsetCorrectionX < start) {
35905
- this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
35906
- this.offsetScrollbarX = this.offsetX;
35907
- this.adjustViewportZoneX();
35908
- }
35909
- while (col < this.left) {
35910
- let leftCol;
35911
- for (leftCol = this.left; leftCol >= 0; leftCol--) {
35912
- if (!this.getters.isColHidden(sheetId, leftCol)) {
35990
+ const { end } = this.getters.getColDimensions(sheetId, targetCol);
35991
+ const maxCol = this.getters.getNumberCols(sheetId);
35992
+ if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
35993
+ for (let col = this.left; this.offsetX + this.offsetCorrectionX + this.viewportWidth < end; col++) {
35994
+ if (col > maxCol) {
35913
35995
  break;
35914
35996
  }
35997
+ if (this.getters.isColHidden(sheetId, col)) {
35998
+ continue;
35999
+ }
36000
+ this.offsetX = this.getters.getColDimensions(sheetId, col).end - this.offsetCorrectionX;
36001
+ this.offsetScrollbarX = this.offsetX;
36002
+ this.adjustViewportZoneX();
36003
+ }
36004
+ }
36005
+ else if (this.left > targetCol) {
36006
+ for (let col = this.left; col >= targetCol; col--) {
36007
+ if (col < 0) {
36008
+ break;
36009
+ }
36010
+ if (this.getters.isColHidden(sheetId, col)) {
36011
+ continue;
36012
+ }
36013
+ this.offsetX = this.getters.getColDimensions(sheetId, col).start - this.offsetCorrectionX;
36014
+ this.offsetScrollbarX = this.offsetX;
36015
+ this.adjustViewportZoneX();
35915
36016
  }
35916
- this.offsetX =
35917
- this.getters.getColDimensions(sheetId, leftCol - 1).start - this.offsetCorrectionX;
35918
- this.offsetScrollbarX = this.offsetX;
35919
- this.adjustViewportZoneX();
35920
36017
  }
35921
36018
  }
35922
- adjustPositionY(row) {
36019
+ adjustPositionY(targetRow) {
35923
36020
  const sheetId = this.sheetId;
35924
- while (this.getters.getRowDimensions(sheetId, row).end >
35925
- this.offsetY + this.height + this.offsetCorrectionY &&
35926
- this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
35927
- this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
35928
- this.offsetScrollbarY = this.offsetY;
35929
- this.adjustViewportZoneY();
35930
- }
35931
- while (row < this.top) {
35932
- let topRow;
35933
- for (topRow = this.top; topRow >= 0; topRow--) {
35934
- if (!this.getters.isRowHidden(sheetId, topRow)) {
36021
+ const { end } = this.getters.getRowDimensions(sheetId, targetRow);
36022
+ const maxRow = this.getters.getNumberRows(sheetId);
36023
+ if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
36024
+ for (let row = this.top; this.offsetY + this.viewportHeight + this.offsetCorrectionY < end; row++) {
36025
+ if (row > maxRow) {
35935
36026
  break;
35936
36027
  }
36028
+ if (this.getters.isRowHidden(sheetId, row)) {
36029
+ continue;
36030
+ }
36031
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).end - this.offsetCorrectionY;
36032
+ this.offsetScrollbarY = this.offsetY;
36033
+ this.adjustViewportZoneY();
36034
+ }
36035
+ }
36036
+ else if (this.top > targetRow) {
36037
+ for (let row = this.top; row >= targetRow; row--) {
36038
+ if (row < 0) {
36039
+ break;
36040
+ }
36041
+ if (this.getters.isRowHidden(sheetId, row)) {
36042
+ continue;
36043
+ }
36044
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).start - this.offsetCorrectionY;
36045
+ this.offsetScrollbarY = this.offsetY;
36046
+ this.adjustViewportZoneY();
35937
36047
  }
35938
- this.offsetY =
35939
- this.getters.getRowDimensions(sheetId, topRow - 1).start - this.offsetCorrectionY;
35940
- this.offsetScrollbarY = this.offsetY;
35941
- this.adjustViewportZoneY();
35942
36048
  }
35943
36049
  }
35944
36050
  setViewportOffset(offsetX, offsetY) {
@@ -35960,8 +36066,8 @@ class InternalViewport {
35960
36066
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
35961
36067
  this.offsetCorrectionX;
35962
36068
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
35963
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
35964
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
36069
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
36070
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
35965
36071
  return {
35966
36072
  x,
35967
36073
  y,
@@ -36024,12 +36130,12 @@ class InternalViewport {
36024
36130
  adjustViewportOffsetX() {
36025
36131
  if (this.canScrollHorizontally) {
36026
36132
  const { width: viewportWidth } = this.getMaxSize();
36027
- if (this.width + this.offsetScrollbarX > viewportWidth) {
36028
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
36133
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
36134
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
36029
36135
  }
36030
36136
  }
36031
36137
  this.left = this.getColIndex(this.offsetScrollbarX, true);
36032
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
36138
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
36033
36139
  if (this.right === -1) {
36034
36140
  this.right = this.boundaries.right;
36035
36141
  }
@@ -36041,12 +36147,12 @@ class InternalViewport {
36041
36147
  adjustViewportOffsetY() {
36042
36148
  if (this.canScrollVertically) {
36043
36149
  const { height: paneHeight } = this.getMaxSize();
36044
- if (this.height + this.offsetScrollbarY > paneHeight) {
36045
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
36150
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
36151
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
36046
36152
  }
36047
36153
  }
36048
36154
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
36049
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
36155
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
36050
36156
  if (this.bottom === -1) {
36051
36157
  this.bottom = this.boundaries.bottom;
36052
36158
  }
@@ -36057,7 +36163,7 @@ class InternalViewport {
36057
36163
  adjustViewportZoneX() {
36058
36164
  const sheetId = this.sheetId;
36059
36165
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
36060
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
36166
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
36061
36167
  if (this.right === -1) {
36062
36168
  this.right = this.getters.getNumberCols(sheetId) - 1;
36063
36169
  }
@@ -36070,7 +36176,7 @@ class InternalViewport {
36070
36176
  adjustViewportZoneY() {
36071
36177
  const sheetId = this.sheetId;
36072
36178
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
36073
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
36179
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
36074
36180
  if (this.bottom === -1) {
36075
36181
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
36076
36182
  }
@@ -36329,8 +36435,7 @@ class SheetViewPlugin extends UIPlugin {
36329
36435
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
36330
36436
  }
36331
36437
  /**
36332
- * Return the main viewport maximum size. That is the zone dimension
36333
- * with some bottom and right padding.
36438
+ * Return the main viewport maximum size relative to the client size.
36334
36439
  */
36335
36440
  getMainViewportRect() {
36336
36441
  const sheetId = this.getters.getActiveSheetId();
@@ -36346,8 +36451,8 @@ class SheetViewPlugin extends UIPlugin {
36346
36451
  const { width, height } = this.getMainViewportRect();
36347
36452
  const viewport = this.getMainInternalViewport(sheetId);
36348
36453
  return {
36349
- maxOffsetX: Math.max(0, width - viewport.width + 1),
36350
- maxOffsetY: Math.max(0, height - viewport.height + 1),
36454
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
36455
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
36351
36456
  };
36352
36457
  }
36353
36458
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -42457,6 +42562,6 @@ function addFunction(functionName, functionDescription) {
42457
42562
  export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, cellTypes, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, load, parse, readonlyAllowedCommands, registries, setTranslationMethod, tokenize };
42458
42563
 
42459
42564
 
42460
- __info__.version = '16.0.5';
42461
- __info__.date = '2023-03-23T11:35:22.974Z';
42462
- __info__.hash = '53150ef';
42565
+ __info__.version = '16.0.7';
42566
+ __info__.date = '2023-04-14T12:46:24.076Z';
42567
+ __info__.hash = '2b4831d';