@odoo/o-spreadsheet 16.2.1 → 16.2.3

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.
@@ -112,88 +112,88 @@ const FILTERS_COLOR = "#188038";
112
112
  const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
113
113
  const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
114
114
  const SEPARATOR_COLOR = "#E0E2E4";
115
- // Color picker
115
+ // Color picker defaults as upper case HEX to match `toHex`helper
116
116
  const COLOR_PICKER_DEFAULTS = [
117
117
  "#000000",
118
118
  "#434343",
119
119
  "#666666",
120
120
  "#999999",
121
- "#b7b7b7",
122
- "#cccccc",
123
- "#d9d9d9",
124
- "#efefef",
125
- "#f3f3f3",
126
- "#ffffff",
121
+ "#B7B7B7",
122
+ "#CCCCCC",
123
+ "#D9D9D9",
124
+ "#EFEFEF",
125
+ "#F3F3F3",
126
+ "#FFFFFF",
127
127
  "#980000",
128
- "#ff0000",
129
- "#ff9900",
130
- "#ffff00",
131
- "#00ff00",
132
- "#00ffff",
133
- "#4a86e8",
134
- "#0000ff",
135
- "#9900ff",
136
- "#ff00ff",
137
- "#e6b8af",
138
- "#f4cccc",
139
- "#fce5cd",
140
- "#fff2cc",
141
- "#d9ead3",
142
- "#d0e0e3",
143
- "#c9daf8",
144
- "#cfe2f3",
145
- "#d9d2e9",
146
- "#ead1dc",
147
- "#dd7e6b",
148
- "#ea9999",
149
- "#f9cb9c",
150
- "#ffe599",
151
- "#b6d7a8",
152
- "#a2c4c9",
153
- "#a4c2f4",
154
- "#9fc5e8",
155
- "#b4a7d6",
156
- "#d5a6bd",
157
- "#cc4125",
158
- "#e06666",
159
- "#f6b26b",
160
- "#ffd966",
161
- "#93c47d",
162
- "#76a5af",
163
- "#6d9eeb",
164
- "#6fa8dc",
165
- "#8e7cc3",
166
- "#c27ba0",
167
- "#a61c00",
168
- "#cc0000",
169
- "#e69138",
170
- "#f1c232",
171
- "#6aa84f",
172
- "#45818e",
173
- "#3c78d8",
174
- "#3d85c6",
175
- "#674ea7",
176
- "#a64d79",
177
- "#85200c",
128
+ "#FF0000",
129
+ "#FF9900",
130
+ "#FFFF00",
131
+ "#00FF00",
132
+ "#00FFFF",
133
+ "#4A86E8",
134
+ "#0000FF",
135
+ "#9900FF",
136
+ "#FF00FF",
137
+ "#E6B8AF",
138
+ "#F4CCCC",
139
+ "#FCE5CD",
140
+ "#FFF2CC",
141
+ "#D9EAD3",
142
+ "#D0E0E3",
143
+ "#C9DAF8",
144
+ "#CFE2F3",
145
+ "#D9D2E9",
146
+ "#EAD1DC",
147
+ "#DD7E6B",
148
+ "#EA9999",
149
+ "#F9CB9C",
150
+ "#FFE599",
151
+ "#B6D7A8",
152
+ "#A2C4C9",
153
+ "#A4C2F4",
154
+ "#9FC5E8",
155
+ "#B4A7D6",
156
+ "#D5A6BD",
157
+ "#CC4125",
158
+ "#E06666",
159
+ "#F6B26B",
160
+ "#FFD966",
161
+ "#93C47D",
162
+ "#76A5AF",
163
+ "#6D9EEB",
164
+ "#6FA8DC",
165
+ "#8E7CC3",
166
+ "#C27BA0",
167
+ "#A61C00",
168
+ "#CC0000",
169
+ "#E69138",
170
+ "#F1C232",
171
+ "#6AA84F",
172
+ "#45818E",
173
+ "#3C78D8",
174
+ "#3D85C6",
175
+ "#674EA7",
176
+ "#A64D79",
177
+ "#85200C",
178
178
  "#990000",
179
- "#b45f06",
180
- "#bf9000",
181
- "#38761d",
182
- "#134f5c",
183
- "#1155cc",
184
- "#0b5394",
185
- "#351c75",
186
- "#741b47",
187
- "#5b0f00",
179
+ "#B45F06",
180
+ "#BF9000",
181
+ "#38761D",
182
+ "#134F5C",
183
+ "#1155CC",
184
+ "#0B5394",
185
+ "#351C75",
186
+ "#741B47",
187
+ "#5B0F00",
188
188
  "#660000",
189
- "#783f04",
190
- "#7f6000",
191
- "#274e13",
192
- "#0c343d",
193
- "#1c4587",
189
+ "#783F04",
190
+ "#7F6000",
191
+ "#274E13",
192
+ "#0C343D",
193
+ "#1C4587",
194
194
  "#073763",
195
- "#20124d",
196
- "#4c1130",
195
+ "#20124D",
196
+ "#4C1130",
197
197
  ];
198
198
  // Dimensions
199
199
  const MIN_ROW_HEIGHT = 10;
@@ -233,7 +233,7 @@ const DEFAULT_FONT = "'Roboto', arial";
233
233
  const DEFAULT_BORDER_DESC = ["thin", "#000"];
234
234
  const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
235
235
  // DateTimeRegex
236
- const DATETIME_FORMAT = /[ymd:]/;
236
+ const DATETIME_FORMAT = /[ymdhs:]/;
237
237
  // Ranges
238
238
  const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
239
239
  // Max Number of history steps kept in memory
@@ -270,11 +270,12 @@ var ComponentsImportance;
270
270
  ComponentsImportance[ComponentsImportance["Highlight"] = 5] = "Highlight";
271
271
  ComponentsImportance[ComponentsImportance["Figure"] = 10] = "Figure";
272
272
  ComponentsImportance[ComponentsImportance["ScrollBar"] = 15] = "ScrollBar";
273
- ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
273
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
274
274
  ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
275
- ComponentsImportance[ComponentsImportance["TopBarComposer"] = 21] = "TopBarComposer";
275
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
276
276
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
277
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
277
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
278
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
278
279
  ComponentsImportance[ComponentsImportance["ChartAnchor"] = 1000] = "ChartAnchor";
279
280
  })(ComponentsImportance || (ComponentsImportance = {}));
280
281
  const DEFAULT_SHEETVIEW_SIZE = 1000;
@@ -701,8 +702,9 @@ function getDefaultCellHeight(cell) {
701
702
  return DEFAULT_CELL_HEIGHT;
702
703
  }
703
704
  const fontSize = computeTextFontSizeInPixels(cell.style);
704
- const multiLineText = cell.content.split(NEWLINE);
705
- return computeTextLinesHeight(fontSize, multiLineText.length) + 2 * PADDING_AUTORESIZE_VERTICAL;
705
+ // the number of lines should be computed from the formula result, but it's not evaluated at this point
706
+ const numberOfLines = cell.isFormula ? 1 : cell.content.split(NEWLINE).length;
707
+ return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
706
708
  }
707
709
  function computeTextWidth(context, text, style) {
708
710
  context.save();
@@ -1054,6 +1056,8 @@ function replaceSpecialSpaces(text) {
1054
1056
  return text;
1055
1057
  }
1056
1058
 
1059
+ const RBA_REGEX = /rgba?\(|\s+|\)/gi;
1060
+ const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
1057
1061
  const colors$1 = [
1058
1062
  "#eb6d00",
1059
1063
  "#0074d9",
@@ -1079,7 +1083,10 @@ function colorNumberString(color) {
1079
1083
  }
1080
1084
  /**
1081
1085
  * Converts any CSS color value to a standardized hex6 value.
1082
- * Accepts: hex3, hex6, hex8 and rgb (rgba is not supported)
1086
+ * Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
1087
+ *
1088
+ * [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
1089
+ * with r,g,b ∈ [0, 255] and a ∈ [0, 1]
1083
1090
  *
1084
1091
  * toHex("#ABC")
1085
1092
  * >> "#AABBCC"
@@ -1090,27 +1097,31 @@ function colorNumberString(color) {
1090
1097
  * toHex("rgb(30, 80, 16)")
1091
1098
  * >> "#1E5010"
1092
1099
  *
1100
+ * * toHex("rgb(30, 80, 16, 0.5)")
1101
+ * >> "#1E501080"
1102
+ *
1093
1103
  */
1094
1104
  function toHex(color) {
1095
- if (color.includes("rgba")) {
1096
- throw new Error(`rgba() conversion currently not supported: ${color}`);
1105
+ let hexColor = color;
1106
+ if (color.startsWith("rgb")) {
1107
+ hexColor = rgbaStringToHex(color);
1097
1108
  }
1098
- if (color.includes("rgb")) {
1099
- return rgbToHex6(color);
1100
- }
1101
- color = color.replace("#", "").toUpperCase();
1102
- if (color.length === 3 || color.length === 4) {
1103
- color = color.split("").reduce((acc, h) => acc + h + h, "");
1109
+ else {
1110
+ hexColor = color.replace("#", "").toUpperCase();
1111
+ if (hexColor.length === 3 || hexColor.length === 4) {
1112
+ hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
1113
+ }
1114
+ hexColor = `#${hexColor}`;
1104
1115
  }
1105
- if (color.replace(/[a-f0-9]/gi, "") !== "") {
1106
- throw new Error("invalid color");
1116
+ if (!hexColor.match(HEX_MATCH)) {
1117
+ throw new Error(`invalid color input: ${color}`);
1107
1118
  }
1108
- return "#" + color;
1119
+ return hexColor;
1109
1120
  }
1110
1121
  function isColorValid(color) {
1111
1122
  try {
1112
- const { r, g, b, a } = colorToRGBA(color);
1113
- return (isColorValueValid(r) && isColorValueValid(g) && isColorValueValid(b) && isColorValueValid(a));
1123
+ toHex(color);
1124
+ return true;
1114
1125
  }
1115
1126
  catch (error) {
1116
1127
  return false;
@@ -1143,15 +1154,29 @@ function relativeLuminance(color) {
1143
1154
  /**
1144
1155
  * Convert a CSS rgb color string to a standardized hex6 color value.
1145
1156
  *
1146
- * rgbToHex6("rgb(30, 80, 16)")
1157
+ * rgbaStringToHex("rgb(30, 80, 16)")
1147
1158
  * >> "#1E5010"
1159
+ *
1160
+ * rgbaStringToHex("rgba(30, 80, 16, 0.5)")
1161
+ * >> "#1E501080"
1162
+ *
1163
+ * DOES NOT SUPPORT NON INTEGER RGB VALUES
1148
1164
  */
1149
- function rgbToHex6(color) {
1150
- return ("#" +
1151
- concat(color
1152
- .slice(4, -1)
1153
- .split(",")
1154
- .map((valueString) => parseInt(valueString, 10).toString(16).padStart(2, "0"))).toUpperCase());
1165
+ function rgbaStringToHex(color) {
1166
+ const stringVals = color.replace(RBA_REGEX, "").split(",");
1167
+ let alphaHex = 255;
1168
+ if (stringVals.length !== 3 && stringVals.length !== 4) {
1169
+ throw new Error("invalid color");
1170
+ }
1171
+ else if (stringVals.length === 4) {
1172
+ const alpha = parseFloat(stringVals.pop() || "1");
1173
+ alphaHex = Math.round((alpha || 1) * 255);
1174
+ }
1175
+ const vals = stringVals.map((val) => parseInt(val, 10));
1176
+ if (alphaHex !== 255) {
1177
+ vals.push(alphaHex);
1178
+ }
1179
+ return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
1155
1180
  }
1156
1181
  /**
1157
1182
  * RGBA to HEX representation (#RRGGBBAA).
@@ -1173,7 +1198,7 @@ function rgbaToHex(rgba) {
1173
1198
  a = "0" + a;
1174
1199
  if (a === "ff")
1175
1200
  a = "";
1176
- return "#" + r + g + b + a;
1201
+ return ("#" + r + g + b + a).toUpperCase();
1177
1202
  }
1178
1203
  /**
1179
1204
  * Color string to RGBA representation
@@ -1294,6 +1319,9 @@ function rgbaToHSLA(rgba) {
1294
1319
  s = +(s * 100).toFixed(1);
1295
1320
  l = +(l * 100).toFixed(1);
1296
1321
  return { a: rgba.a, h, s, l };
1322
+ }
1323
+ function isSameColor(color1, color2) {
1324
+ return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
1297
1325
  }
1298
1326
 
1299
1327
  /** Reference of a cell (eg. A1, $B$5) */
@@ -1445,7 +1473,7 @@ function scrollDelay(value) {
1445
1473
  * formula, commas are used to separate arguments
1446
1474
  * - it does not support % symbol, in formulas % is an operator
1447
1475
  */
1448
- const formulaNumberRegexp = /^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+/;
1476
+ const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
1449
1477
  const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
1450
1478
  const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
1451
1479
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -3051,6 +3079,7 @@ const CHART_PADDING_RATIO = 0.02;
3051
3079
  const LINE_HEIGHT = 1.2;
3052
3080
  css /* scss */ `
3053
3081
  div.o-scorecard {
3082
+ font-family: ${DEFAULT_FONT};
3054
3083
  user-select: none;
3055
3084
  background-color: white;
3056
3085
  display: flex;
@@ -5101,6 +5130,11 @@ class Popover extends Component {
5101
5130
  this.currentPosition = newPosition;
5102
5131
  });
5103
5132
  }
5133
+ get popoverStyle() {
5134
+ return cssPropertiesToCss({
5135
+ "z-index": `${this.props.zIndex}`,
5136
+ });
5137
+ }
5104
5138
  }
5105
5139
  Popover.template = "o-spreadsheet-Popover";
5106
5140
  Popover.defaultProps = {
@@ -5109,6 +5143,7 @@ Popover.defaultProps = {
5109
5143
  onMouseWheel: () => { },
5110
5144
  onPopoverMoved: () => { },
5111
5145
  onPopoverHidden: () => { },
5146
+ zIndex: ComponentsImportance.Popover,
5112
5147
  };
5113
5148
  Popover.props = {
5114
5149
  anchorRect: Object,
@@ -5120,6 +5155,7 @@ Popover.props = {
5120
5155
  onMouseWheel: { type: Function, optional: true },
5121
5156
  onPopoverHidden: { type: Function, optional: true },
5122
5157
  onPopoverMoved: { type: Function, optional: true },
5158
+ zIndex: { type: Number, optional: true },
5123
5159
  slots: Object,
5124
5160
  };
5125
5161
  class PopoverPositionContext {
@@ -17010,6 +17046,9 @@ class ColorPicker extends Component {
17010
17046
  top,
17011
17047
  });
17012
17048
  }
17049
+ isSameColor(color1, color2) {
17050
+ return isSameColor(color1, color2);
17051
+ }
17013
17052
  }
17014
17053
  ColorPicker.template = "o-spreadsheet-ColorPicker";
17015
17054
  ColorPicker.defaultProps = {
@@ -19251,6 +19290,8 @@ class ContentEditableHelper {
19251
19290
  start = 0;
19252
19291
  if (end > textLength)
19253
19292
  end = textLength;
19293
+ if (start > textLength)
19294
+ start = textLength;
19254
19295
  }
19255
19296
  let startNode = this.findChildAtCharacterIndex(start);
19256
19297
  let endNode = this.findChildAtCharacterIndex(end);
@@ -19520,6 +19561,7 @@ css /* scss */ `
19520
19561
  padding-right: 2px;
19521
19562
 
19522
19563
  box-sizing: border-box;
19564
+ font-family: ${DEFAULT_FONT};
19523
19565
 
19524
19566
  caret-color: black;
19525
19567
  padding-left: 3px;
@@ -20789,6 +20831,10 @@ GridOverlay.props = {
20789
20831
  };
20790
20832
 
20791
20833
  class GridPopover extends Component {
20834
+ constructor() {
20835
+ super(...arguments);
20836
+ this.zIndex = ComponentsImportance.GridPopover;
20837
+ }
20792
20838
  get cellPopover() {
20793
20839
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
20794
20840
  if (!popover.isOpen) {
@@ -22153,6 +22199,10 @@ class Grid extends Component {
22153
22199
  }
22154
22200
  }
22155
22201
  onInput(ev) {
22202
+ // the user meant to paste in the sheet, not open the composer with the pasted content
22203
+ if (!ev.isComposing && ev.inputType === "insertFromPaste") {
22204
+ return;
22205
+ }
22156
22206
  if (ev.data) {
22157
22207
  // if the user types a character on the grid, it means he wants to start composing the selected cell with that
22158
22208
  // character
@@ -23001,6 +23051,70 @@ function fixXlsxUnicode(str) {
23001
23051
  });
23002
23052
  }
23003
23053
 
23054
+ 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;
23055
+ /**
23056
+ * Convert excel format to o_spreadsheet format
23057
+ *
23058
+ * Excel format are defined in openXML §18.8.31
23059
+ */
23060
+ function convertXlsxFormat(numFmtId, formats, warningManager) {
23061
+ var _a, _b, _c;
23062
+ if (numFmtId === 0) {
23063
+ return undefined;
23064
+ }
23065
+ // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23066
+ let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23067
+ if (format) {
23068
+ try {
23069
+ let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23070
+ convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23071
+ convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23072
+ // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23073
+ const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23074
+ const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23075
+ if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23076
+ throw new Error("Multiple escaped blocks in format");
23077
+ }
23078
+ convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23079
+ convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
23080
+ convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23081
+ convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23082
+ convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
23083
+ if (isXlsxDateFormat(convertedFormat)) {
23084
+ convertedFormat = convertDateFormat$1(convertedFormat);
23085
+ }
23086
+ if (isFormatSupported(convertedFormat)) {
23087
+ return convertedFormat;
23088
+ }
23089
+ }
23090
+ catch (e) { }
23091
+ }
23092
+ warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23093
+ return undefined;
23094
+ }
23095
+ function isFormatSupported(format) {
23096
+ try {
23097
+ formatValue(0, format);
23098
+ return true;
23099
+ }
23100
+ catch (e) {
23101
+ return false;
23102
+ }
23103
+ }
23104
+ function isXlsxDateFormat(format) {
23105
+ return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
23106
+ }
23107
+ function convertDateFormat$1(format) {
23108
+ // Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
23109
+ // but can still occur and are supported by Excel/Google sheets
23110
+ format = format.toLowerCase();
23111
+ format = format.replace(/mmmmm/g, "mmm");
23112
+ format = format.replace(/am\/pm|a\/m/g, "a");
23113
+ format = format.replace(/hhhh/g, "hh");
23114
+ format = format.replace(/\bh\b/g, "hh");
23115
+ return format;
23116
+ }
23117
+
23004
23118
  function convertBorders(data, warningManager) {
23005
23119
  const borderArray = data.borders.map((border) => {
23006
23120
  addBorderWarnings(border, warningManager);
@@ -23063,41 +23177,6 @@ function convertFormats(data, warningManager) {
23063
23177
  }
23064
23178
  return arrayToObject(formats, 1);
23065
23179
  }
23066
- /**
23067
- * Convert excel format to o_spreadsheet format
23068
- *
23069
- * Excel format are defined in openXML §18.8.31
23070
- */
23071
- function convertXlsxFormat(numFmtId, formats, warningManager) {
23072
- var _a, _b, _c;
23073
- if (numFmtId === 0) {
23074
- return undefined;
23075
- }
23076
- // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23077
- let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23078
- if (format) {
23079
- try {
23080
- let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23081
- convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23082
- convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23083
- // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23084
- const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23085
- const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23086
- if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23087
- throw new Error("Multiple escaped blocks in format");
23088
- }
23089
- convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23090
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
23091
- convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23092
- convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23093
- formatValue(0, convertedFormat);
23094
- return convertedFormat;
23095
- }
23096
- catch (e) { }
23097
- }
23098
- warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23099
- return undefined;
23100
- }
23101
23180
  // ---------------------------------------------------------------------------
23102
23181
  // Warnings
23103
23182
  // ---------------------------------------------------------------------------
@@ -31396,9 +31475,7 @@ class CustomColorsPlugin extends UIPlugin {
31396
31475
  // remove duplicates first to check validity on a reduced
31397
31476
  // set of colors, then normalize to HEX and remove duplicates
31398
31477
  // again
31399
- [...new Set([...usedColors, ...this.customColors])]
31400
- .filter(isColorValid)
31401
- .map((c) => toHex(c).toLowerCase())),
31478
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
31402
31479
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
31403
31480
  }
31404
31481
  getColorsFromCells(cells) {
@@ -31459,7 +31536,7 @@ class CustomColorsPlugin extends UIPlugin {
31459
31536
  return [...chartsColors];
31460
31537
  }
31461
31538
  tryToAddColor(color) {
31462
- const formattedColor = toHex(color).toLowerCase();
31539
+ const formattedColor = toHex(color);
31463
31540
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
31464
31541
  this.customColors.add(formattedColor);
31465
31542
  }
@@ -32474,8 +32551,8 @@ class InternalViewport {
32474
32551
  this.getters = getters;
32475
32552
  this.sheetId = sheetId;
32476
32553
  this.boundaries = boundaries;
32477
- this.width = sizeInGrid.width;
32478
- this.height = sizeInGrid.height;
32554
+ this.viewportWidth = sizeInGrid.width;
32555
+ this.viewportHeight = sizeInGrid.height;
32479
32556
  this.offsetScrollbarX = offsets.x;
32480
32557
  this.offsetScrollbarY = offsets.y;
32481
32558
  this.canScrollVertically = options.canScrollVertically;
@@ -32486,6 +32563,10 @@ class InternalViewport {
32486
32563
  this.adjustViewportOffsetY();
32487
32564
  }
32488
32565
  // PUBLIC
32566
+ /** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
32567
+ * When the viewport grid size is smaller than its client width (resp. height), it will return
32568
+ * the client width (resp. height).
32569
+ */
32489
32570
  getMaxSize() {
32490
32571
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
32491
32572
  first: this.boundaries.left,
@@ -32497,20 +32578,24 @@ class InternalViewport {
32497
32578
  });
32498
32579
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
32499
32580
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
32500
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
32581
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
32501
32582
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
32502
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
32583
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
32503
32584
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
32504
- const width = lastColEnd -
32505
- this.offsetCorrectionX +
32506
- (this.canScrollHorizontally
32507
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
32508
- : 0);
32509
- const height = lastRowEnd -
32510
- this.offsetCorrectionY +
32511
- (this.canScrollVertically
32512
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
32513
- : 0);
32585
+ let width = lastColEnd - this.offsetCorrectionX;
32586
+ if (this.canScrollHorizontally) {
32587
+ width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
32588
+ Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
32589
+ );
32590
+ width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
32591
+ }
32592
+ let height = lastRowEnd - this.offsetCorrectionY;
32593
+ if (this.canScrollVertically) {
32594
+ height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
32595
+ Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
32596
+ );
32597
+ height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
32598
+ }
32514
32599
  return { width, height };
32515
32600
  }
32516
32601
  /**
@@ -32519,7 +32604,7 @@ class InternalViewport {
32519
32604
  * It returns -1 if no column is found.
32520
32605
  */
32521
32606
  getColIndex(x, absolute = false) {
32522
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
32607
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
32523
32608
  return -1;
32524
32609
  }
32525
32610
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -32530,7 +32615,7 @@ class InternalViewport {
32530
32615
  * It returns -1 if no row is found.
32531
32616
  */
32532
32617
  getRowIndex(y, absolute = false) {
32533
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
32618
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
32534
32619
  return -1;
32535
32620
  }
32536
32621
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -32554,48 +32639,66 @@ class InternalViewport {
32554
32639
  this.adjustPositionY(row);
32555
32640
  }
32556
32641
  }
32557
- adjustPositionX(col) {
32642
+ adjustPositionX(targetCol) {
32558
32643
  const sheetId = this.sheetId;
32559
- const { start, end } = this.getters.getColDimensions(sheetId, col);
32560
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
32561
- this.offsetX + this.offsetCorrectionX < start) {
32562
- this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
32563
- this.offsetScrollbarX = this.offsetX;
32564
- this.adjustViewportZoneX();
32565
- }
32566
- while (col < this.left) {
32567
- let leftCol;
32568
- for (leftCol = this.left; leftCol >= 0; leftCol--) {
32569
- if (!this.getters.isColHidden(sheetId, leftCol)) {
32644
+ const { end } = this.getters.getColDimensions(sheetId, targetCol);
32645
+ const maxCol = this.getters.getNumberCols(sheetId);
32646
+ if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
32647
+ for (let col = this.left; this.offsetX + this.offsetCorrectionX + this.viewportWidth < end; col++) {
32648
+ if (col > maxCol) {
32649
+ break;
32650
+ }
32651
+ if (this.getters.isColHidden(sheetId, col)) {
32652
+ continue;
32653
+ }
32654
+ this.offsetX = this.getters.getColDimensions(sheetId, col).end - this.offsetCorrectionX;
32655
+ this.offsetScrollbarX = this.offsetX;
32656
+ this.adjustViewportZoneX();
32657
+ }
32658
+ }
32659
+ else if (this.left > targetCol) {
32660
+ for (let col = this.left; col >= targetCol; col--) {
32661
+ if (col < 0) {
32570
32662
  break;
32571
32663
  }
32664
+ if (this.getters.isColHidden(sheetId, col)) {
32665
+ continue;
32666
+ }
32667
+ this.offsetX = this.getters.getColDimensions(sheetId, col).start - this.offsetCorrectionX;
32668
+ this.offsetScrollbarX = this.offsetX;
32669
+ this.adjustViewportZoneX();
32572
32670
  }
32573
- this.offsetX =
32574
- this.getters.getColDimensions(sheetId, leftCol - 1).start - this.offsetCorrectionX;
32575
- this.offsetScrollbarX = this.offsetX;
32576
- this.adjustViewportZoneX();
32577
32671
  }
32578
32672
  }
32579
- adjustPositionY(row) {
32673
+ adjustPositionY(targetRow) {
32580
32674
  const sheetId = this.sheetId;
32581
- while (this.getters.getRowDimensions(sheetId, row).end >
32582
- this.offsetY + this.height + this.offsetCorrectionY &&
32583
- this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
32584
- this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
32585
- this.offsetScrollbarY = this.offsetY;
32586
- this.adjustViewportZoneY();
32587
- }
32588
- while (row < this.top) {
32589
- let topRow;
32590
- for (topRow = this.top; topRow >= 0; topRow--) {
32591
- if (!this.getters.isRowHidden(sheetId, topRow)) {
32675
+ const { end } = this.getters.getRowDimensions(sheetId, targetRow);
32676
+ const maxRow = this.getters.getNumberRows(sheetId);
32677
+ if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
32678
+ for (let row = this.top; this.offsetY + this.viewportHeight + this.offsetCorrectionY < end; row++) {
32679
+ if (row > maxRow) {
32592
32680
  break;
32593
32681
  }
32682
+ if (this.getters.isRowHidden(sheetId, row)) {
32683
+ continue;
32684
+ }
32685
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).end - this.offsetCorrectionY;
32686
+ this.offsetScrollbarY = this.offsetY;
32687
+ this.adjustViewportZoneY();
32688
+ }
32689
+ }
32690
+ else if (this.top > targetRow) {
32691
+ for (let row = this.top; row >= targetRow; row--) {
32692
+ if (row < 0) {
32693
+ break;
32694
+ }
32695
+ if (this.getters.isRowHidden(sheetId, row)) {
32696
+ continue;
32697
+ }
32698
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).start - this.offsetCorrectionY;
32699
+ this.offsetScrollbarY = this.offsetY;
32700
+ this.adjustViewportZoneY();
32594
32701
  }
32595
- this.offsetY =
32596
- this.getters.getRowDimensions(sheetId, topRow - 1).start - this.offsetCorrectionY;
32597
- this.offsetScrollbarY = this.offsetY;
32598
- this.adjustViewportZoneY();
32599
32702
  }
32600
32703
  }
32601
32704
  setViewportOffset(offsetX, offsetY) {
@@ -32617,8 +32720,8 @@ class InternalViewport {
32617
32720
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
32618
32721
  this.offsetCorrectionX;
32619
32722
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
32620
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
32621
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
32723
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
32724
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
32622
32725
  return {
32623
32726
  x,
32624
32727
  y,
@@ -32681,12 +32784,12 @@ class InternalViewport {
32681
32784
  adjustViewportOffsetX() {
32682
32785
  if (this.canScrollHorizontally) {
32683
32786
  const { width: viewportWidth } = this.getMaxSize();
32684
- if (this.width + this.offsetScrollbarX > viewportWidth) {
32685
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
32787
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
32788
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
32686
32789
  }
32687
32790
  }
32688
32791
  this.left = this.getColIndex(this.offsetScrollbarX, true);
32689
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
32792
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
32690
32793
  if (this.right === -1) {
32691
32794
  this.right = this.boundaries.right;
32692
32795
  }
@@ -32698,12 +32801,12 @@ class InternalViewport {
32698
32801
  adjustViewportOffsetY() {
32699
32802
  if (this.canScrollVertically) {
32700
32803
  const { height: paneHeight } = this.getMaxSize();
32701
- if (this.height + this.offsetScrollbarY > paneHeight) {
32702
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
32804
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
32805
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
32703
32806
  }
32704
32807
  }
32705
32808
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
32706
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
32809
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
32707
32810
  if (this.bottom === -1) {
32708
32811
  this.bottom = this.boundaries.bottom;
32709
32812
  }
@@ -32714,7 +32817,7 @@ class InternalViewport {
32714
32817
  adjustViewportZoneX() {
32715
32818
  const sheetId = this.sheetId;
32716
32819
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
32717
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
32820
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
32718
32821
  if (this.right === -1) {
32719
32822
  this.right = this.getters.getNumberCols(sheetId) - 1;
32720
32823
  }
@@ -32727,7 +32830,7 @@ class InternalViewport {
32727
32830
  adjustViewportZoneY() {
32728
32831
  const sheetId = this.sheetId;
32729
32832
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
32730
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
32833
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
32731
32834
  if (this.bottom === -1) {
32732
32835
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
32733
32836
  }
@@ -32990,8 +33093,7 @@ class SheetViewPlugin extends UIPlugin {
32990
33093
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
32991
33094
  }
32992
33095
  /**
32993
- * Return the main viewport maximum size. That is the zone dimension
32994
- * with some bottom and right padding.
33096
+ * Return the main viewport maximum size relative to the client size.
32995
33097
  */
32996
33098
  getMainViewportRect() {
32997
33099
  const sheetId = this.getters.getActiveSheetId();
@@ -33007,8 +33109,8 @@ class SheetViewPlugin extends UIPlugin {
33007
33109
  const { width, height } = this.getMainViewportRect();
33008
33110
  const viewport = this.getMainInternalViewport(sheetId);
33009
33111
  return {
33010
- maxOffsetX: Math.max(0, width - viewport.width + 1),
33011
- maxOffsetY: Math.max(0, height - viewport.height + 1),
33112
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
33113
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
33012
33114
  };
33013
33115
  }
33014
33116
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -41121,9 +41223,6 @@ css /* scss */ `
41121
41223
  color: #333;
41122
41224
  }
41123
41225
 
41124
- * {
41125
- font-family: "Roboto", "RobotoDraft", Helvetica, Arial, sans-serif;
41126
- }
41127
41226
  &,
41128
41227
  *,
41129
41228
  *:before,
@@ -44961,6 +45060,6 @@ function addFunction(functionName, functionDescription) {
44961
45060
  export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setTranslationMethod, tokenize };
44962
45061
 
44963
45062
 
44964
- __info__.version = '16.2.1';
44965
- __info__.date = '2023-03-23T11:35:41.982Z';
44966
- __info__.hash = 'd1e5470';
45063
+ __info__.version = '16.2.3';
45064
+ __info__.date = '2023-04-14T12:47:50.453Z';
45065
+ __info__.hash = '4514375';