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