@odoo/o-spreadsheet 16.2.0 → 16.2.2

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;
@@ -20730,6 +20772,9 @@ class GridOverlay extends Component {
20730
20772
  onMounted(() => {
20731
20773
  resizeObserver.observe(this.gridOverlayEl);
20732
20774
  });
20775
+ onWillUnmount(() => {
20776
+ resizeObserver.disconnect();
20777
+ });
20733
20778
  useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
20734
20779
  const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
20735
20780
  return scrollY > 0;
@@ -20786,6 +20831,10 @@ GridOverlay.props = {
20786
20831
  };
20787
20832
 
20788
20833
  class GridPopover extends Component {
20834
+ constructor() {
20835
+ super(...arguments);
20836
+ this.zIndex = ComponentsImportance.GridPopover;
20837
+ }
20789
20838
  get cellPopover() {
20790
20839
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
20791
20840
  if (!popover.isOpen) {
@@ -22150,6 +22199,10 @@ class Grid extends Component {
22150
22199
  }
22151
22200
  }
22152
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
+ }
22153
22206
  if (ev.data) {
22154
22207
  // if the user types a character on the grid, it means he wants to start composing the selected cell with that
22155
22208
  // character
@@ -22998,6 +23051,70 @@ function fixXlsxUnicode(str) {
22998
23051
  });
22999
23052
  }
23000
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
+
23001
23118
  function convertBorders(data, warningManager) {
23002
23119
  const borderArray = data.borders.map((border) => {
23003
23120
  addBorderWarnings(border, warningManager);
@@ -23060,41 +23177,6 @@ function convertFormats(data, warningManager) {
23060
23177
  }
23061
23178
  return arrayToObject(formats, 1);
23062
23179
  }
23063
- /**
23064
- * Convert excel format to o_spreadsheet format
23065
- *
23066
- * Excel format are defined in openXML §18.8.31
23067
- */
23068
- function convertXlsxFormat(numFmtId, formats, warningManager) {
23069
- var _a, _b, _c;
23070
- if (numFmtId === 0) {
23071
- return undefined;
23072
- }
23073
- // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23074
- let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23075
- if (format) {
23076
- try {
23077
- let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23078
- convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23079
- convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23080
- // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23081
- const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23082
- const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23083
- if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23084
- throw new Error("Multiple escaped blocks in format");
23085
- }
23086
- convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23087
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
23088
- convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23089
- convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23090
- formatValue(0, convertedFormat);
23091
- return convertedFormat;
23092
- }
23093
- catch (e) { }
23094
- }
23095
- warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23096
- return undefined;
23097
- }
23098
23180
  // ---------------------------------------------------------------------------
23099
23181
  // Warnings
23100
23182
  // ---------------------------------------------------------------------------
@@ -30086,6 +30168,7 @@ class RangeAdapter {
30086
30168
  }
30087
30169
  else if (range.zone[start] >= min && range.zone[end] <= max) {
30088
30170
  changeType = "REMOVE";
30171
+ newRange = range.clone({ ...this.getInvalidRange() });
30089
30172
  }
30090
30173
  else if (range.zone[start] <= max && range.zone[end] >= max) {
30091
30174
  const toRemove = max - range.zone[start] + 1;
@@ -30151,8 +30234,10 @@ class RangeAdapter {
30151
30234
  return { changeType: "NONE" };
30152
30235
  }
30153
30236
  const invalidSheetName = this.getters.getSheetName(cmd.sheetId);
30154
- const sheetId = "";
30155
- range = range.clone({ sheetId, invalidSheetName });
30237
+ range = range.clone({
30238
+ ...this.getInvalidRange(),
30239
+ invalidSheetName,
30240
+ });
30156
30241
  return { changeType: "REMOVE", range };
30157
30242
  }, cmd.sheetId);
30158
30243
  break;
@@ -30412,6 +30497,15 @@ class RangeAdapter {
30412
30497
  }
30413
30498
  return str;
30414
30499
  }
30500
+ getInvalidRange() {
30501
+ return {
30502
+ parts: [],
30503
+ prefixSheet: false,
30504
+ zone: { left: -1, top: -1, right: -1, bottom: -1 },
30505
+ sheetId: "",
30506
+ invalidXc: INCORRECT_RANGE_STRING,
30507
+ };
30508
+ }
30415
30509
  }
30416
30510
  RangeAdapter.getters = [
30417
30511
  "getRangeString",
@@ -31381,9 +31475,7 @@ class CustomColorsPlugin extends UIPlugin {
31381
31475
  // remove duplicates first to check validity on a reduced
31382
31476
  // set of colors, then normalize to HEX and remove duplicates
31383
31477
  // again
31384
- [...new Set([...usedColors, ...this.customColors])]
31385
- .filter(isColorValid)
31386
- .map((c) => toHex(c).toLowerCase())),
31478
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
31387
31479
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
31388
31480
  }
31389
31481
  getColorsFromCells(cells) {
@@ -31444,7 +31536,7 @@ class CustomColorsPlugin extends UIPlugin {
31444
31536
  return [...chartsColors];
31445
31537
  }
31446
31538
  tryToAddColor(color) {
31447
- const formattedColor = toHex(color).toLowerCase();
31539
+ const formattedColor = toHex(color);
31448
31540
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
31449
31541
  this.customColors.add(formattedColor);
31450
31542
  }
@@ -32459,8 +32551,8 @@ class InternalViewport {
32459
32551
  this.getters = getters;
32460
32552
  this.sheetId = sheetId;
32461
32553
  this.boundaries = boundaries;
32462
- this.width = sizeInGrid.width;
32463
- this.height = sizeInGrid.height;
32554
+ this.viewportWidth = sizeInGrid.width;
32555
+ this.viewportHeight = sizeInGrid.height;
32464
32556
  this.offsetScrollbarX = offsets.x;
32465
32557
  this.offsetScrollbarY = offsets.y;
32466
32558
  this.canScrollVertically = options.canScrollVertically;
@@ -32471,6 +32563,10 @@ class InternalViewport {
32471
32563
  this.adjustViewportOffsetY();
32472
32564
  }
32473
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
+ */
32474
32570
  getMaxSize() {
32475
32571
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
32476
32572
  first: this.boundaries.left,
@@ -32482,20 +32578,24 @@ class InternalViewport {
32482
32578
  });
32483
32579
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
32484
32580
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
32485
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
32581
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
32486
32582
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
32487
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
32583
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
32488
32584
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
32489
- const width = lastColEnd -
32490
- this.offsetCorrectionX +
32491
- (this.canScrollHorizontally
32492
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
32493
- : 0);
32494
- const height = lastRowEnd -
32495
- this.offsetCorrectionY +
32496
- (this.canScrollVertically
32497
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
32498
- : 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
+ }
32499
32599
  return { width, height };
32500
32600
  }
32501
32601
  /**
@@ -32504,7 +32604,7 @@ class InternalViewport {
32504
32604
  * It returns -1 if no column is found.
32505
32605
  */
32506
32606
  getColIndex(x, absolute = false) {
32507
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
32607
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
32508
32608
  return -1;
32509
32609
  }
32510
32610
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -32515,7 +32615,7 @@ class InternalViewport {
32515
32615
  * It returns -1 if no row is found.
32516
32616
  */
32517
32617
  getRowIndex(y, absolute = false) {
32518
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
32618
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
32519
32619
  return -1;
32520
32620
  }
32521
32621
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -32542,7 +32642,7 @@ class InternalViewport {
32542
32642
  adjustPositionX(col) {
32543
32643
  const sheetId = this.sheetId;
32544
32644
  const { start, end } = this.getters.getColDimensions(sheetId, col);
32545
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
32645
+ while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
32546
32646
  this.offsetX + this.offsetCorrectionX < start) {
32547
32647
  this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
32548
32648
  this.offsetScrollbarX = this.offsetX;
@@ -32564,7 +32664,7 @@ class InternalViewport {
32564
32664
  adjustPositionY(row) {
32565
32665
  const sheetId = this.sheetId;
32566
32666
  while (this.getters.getRowDimensions(sheetId, row).end >
32567
- this.offsetY + this.height + this.offsetCorrectionY &&
32667
+ this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
32568
32668
  this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
32569
32669
  this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
32570
32670
  this.offsetScrollbarY = this.offsetY;
@@ -32602,8 +32702,8 @@ class InternalViewport {
32602
32702
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
32603
32703
  this.offsetCorrectionX;
32604
32704
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
32605
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
32606
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
32705
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
32706
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
32607
32707
  return {
32608
32708
  x,
32609
32709
  y,
@@ -32666,12 +32766,12 @@ class InternalViewport {
32666
32766
  adjustViewportOffsetX() {
32667
32767
  if (this.canScrollHorizontally) {
32668
32768
  const { width: viewportWidth } = this.getMaxSize();
32669
- if (this.width + this.offsetScrollbarX > viewportWidth) {
32670
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
32769
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
32770
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
32671
32771
  }
32672
32772
  }
32673
32773
  this.left = this.getColIndex(this.offsetScrollbarX, true);
32674
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
32774
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
32675
32775
  if (this.right === -1) {
32676
32776
  this.right = this.boundaries.right;
32677
32777
  }
@@ -32683,12 +32783,12 @@ class InternalViewport {
32683
32783
  adjustViewportOffsetY() {
32684
32784
  if (this.canScrollVertically) {
32685
32785
  const { height: paneHeight } = this.getMaxSize();
32686
- if (this.height + this.offsetScrollbarY > paneHeight) {
32687
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
32786
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
32787
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
32688
32788
  }
32689
32789
  }
32690
32790
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
32691
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
32791
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
32692
32792
  if (this.bottom === -1) {
32693
32793
  this.bottom = this.boundaries.bottom;
32694
32794
  }
@@ -32699,7 +32799,7 @@ class InternalViewport {
32699
32799
  adjustViewportZoneX() {
32700
32800
  const sheetId = this.sheetId;
32701
32801
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
32702
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
32802
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
32703
32803
  if (this.right === -1) {
32704
32804
  this.right = this.getters.getNumberCols(sheetId) - 1;
32705
32805
  }
@@ -32712,7 +32812,7 @@ class InternalViewport {
32712
32812
  adjustViewportZoneY() {
32713
32813
  const sheetId = this.sheetId;
32714
32814
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
32715
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
32815
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
32716
32816
  if (this.bottom === -1) {
32717
32817
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
32718
32818
  }
@@ -32975,8 +33075,7 @@ class SheetViewPlugin extends UIPlugin {
32975
33075
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
32976
33076
  }
32977
33077
  /**
32978
- * Return the main viewport maximum size. That is the zone dimension
32979
- * with some bottom and right padding.
33078
+ * Return the main viewport maximum size relative to the client size.
32980
33079
  */
32981
33080
  getMainViewportRect() {
32982
33081
  const sheetId = this.getters.getActiveSheetId();
@@ -32992,8 +33091,8 @@ class SheetViewPlugin extends UIPlugin {
32992
33091
  const { width, height } = this.getMainViewportRect();
32993
33092
  const viewport = this.getMainInternalViewport(sheetId);
32994
33093
  return {
32995
- maxOffsetX: Math.max(0, width - viewport.width + 1),
32996
- maxOffsetY: Math.max(0, height - viewport.height + 1),
33094
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
33095
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
32997
33096
  };
32998
33097
  }
32999
33098
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -40892,6 +40991,7 @@ class TopBar extends Component {
40892
40991
  this.state.menuState.parentMenu = menu;
40893
40992
  this.isSelectingMenu = true;
40894
40993
  this.openedEl = ev.target;
40994
+ this.env.model.dispatch("STOP_EDITION");
40895
40995
  }
40896
40996
  closeMenus() {
40897
40997
  this.state.activeTool = "";
@@ -41105,9 +41205,6 @@ css /* scss */ `
41105
41205
  color: #333;
41106
41206
  }
41107
41207
 
41108
- * {
41109
- font-family: "Roboto", "RobotoDraft", Helvetica, Arial, sans-serif;
41110
- }
41111
41208
  &,
41112
41209
  *,
41113
41210
  *:before,
@@ -44945,6 +45042,6 @@ function addFunction(functionName, functionDescription) {
44945
45042
  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 };
44946
45043
 
44947
45044
 
44948
- __info__.version = '16.2.0';
44949
- __info__.date = '2023-03-15T15:03:34.107Z';
44950
- __info__.hash = 'c74b1d1';
45045
+ __info__.version = '16.2.2';
45046
+ __info__.date = '2023-04-13T08:29:22.236Z';
45047
+ __info__.hash = 'a38f31a';