@odoo/o-spreadsheet 16.0.4 → 16.0.6

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.
@@ -115,88 +115,88 @@ const LINK_COLOR = "#01666b";
115
115
  const FILTERS_COLOR = "#188038";
116
116
  const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
117
117
  const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
118
- // Color picker
118
+ // Color picker defaults as upper case HEX to match `toHex`helper
119
119
  const COLOR_PICKER_DEFAULTS = [
120
120
  "#000000",
121
121
  "#434343",
122
122
  "#666666",
123
123
  "#999999",
124
- "#b7b7b7",
125
- "#cccccc",
126
- "#d9d9d9",
127
- "#efefef",
128
- "#f3f3f3",
129
- "#ffffff",
124
+ "#B7B7B7",
125
+ "#CCCCCC",
126
+ "#D9D9D9",
127
+ "#EFEFEF",
128
+ "#F3F3F3",
129
+ "#FFFFFF",
130
130
  "#980000",
131
- "#ff0000",
132
- "#ff9900",
133
- "#ffff00",
134
- "#00ff00",
135
- "#00ffff",
136
- "#4a86e8",
137
- "#0000ff",
138
- "#9900ff",
139
- "#ff00ff",
140
- "#e6b8af",
141
- "#f4cccc",
142
- "#fce5cd",
143
- "#fff2cc",
144
- "#d9ead3",
145
- "#d0e0e3",
146
- "#c9daf8",
147
- "#cfe2f3",
148
- "#d9d2e9",
149
- "#ead1dc",
150
- "#dd7e6b",
151
- "#ea9999",
152
- "#f9cb9c",
153
- "#ffe599",
154
- "#b6d7a8",
155
- "#a2c4c9",
156
- "#a4c2f4",
157
- "#9fc5e8",
158
- "#b4a7d6",
159
- "#d5a6bd",
160
- "#cc4125",
161
- "#e06666",
162
- "#f6b26b",
163
- "#ffd966",
164
- "#93c47d",
165
- "#76a5af",
166
- "#6d9eeb",
167
- "#6fa8dc",
168
- "#8e7cc3",
169
- "#c27ba0",
170
- "#a61c00",
171
- "#cc0000",
172
- "#e69138",
173
- "#f1c232",
174
- "#6aa84f",
175
- "#45818e",
176
- "#3c78d8",
177
- "#3d85c6",
178
- "#674ea7",
179
- "#a64d79",
180
- "#85200c",
131
+ "#FF0000",
132
+ "#FF9900",
133
+ "#FFFF00",
134
+ "#00FF00",
135
+ "#00FFFF",
136
+ "#4A86E8",
137
+ "#0000FF",
138
+ "#9900FF",
139
+ "#FF00FF",
140
+ "#E6B8AF",
141
+ "#F4CCCC",
142
+ "#FCE5CD",
143
+ "#FFF2CC",
144
+ "#D9EAD3",
145
+ "#D0E0E3",
146
+ "#C9DAF8",
147
+ "#CFE2F3",
148
+ "#D9D2E9",
149
+ "#EAD1DC",
150
+ "#DD7E6B",
151
+ "#EA9999",
152
+ "#F9CB9C",
153
+ "#FFE599",
154
+ "#B6D7A8",
155
+ "#A2C4C9",
156
+ "#A4C2F4",
157
+ "#9FC5E8",
158
+ "#B4A7D6",
159
+ "#D5A6BD",
160
+ "#CC4125",
161
+ "#E06666",
162
+ "#F6B26B",
163
+ "#FFD966",
164
+ "#93C47D",
165
+ "#76A5AF",
166
+ "#6D9EEB",
167
+ "#6FA8DC",
168
+ "#8E7CC3",
169
+ "#C27BA0",
170
+ "#A61C00",
171
+ "#CC0000",
172
+ "#E69138",
173
+ "#F1C232",
174
+ "#6AA84F",
175
+ "#45818E",
176
+ "#3C78D8",
177
+ "#3D85C6",
178
+ "#674EA7",
179
+ "#A64D79",
180
+ "#85200C",
181
181
  "#990000",
182
- "#b45f06",
183
- "#bf9000",
184
- "#38761d",
185
- "#134f5c",
186
- "#1155cc",
187
- "#0b5394",
188
- "#351c75",
189
- "#741b47",
190
- "#5b0f00",
182
+ "#B45F06",
183
+ "#BF9000",
184
+ "#38761D",
185
+ "#134F5C",
186
+ "#1155CC",
187
+ "#0B5394",
188
+ "#351C75",
189
+ "#741B47",
190
+ "#5B0F00",
191
191
  "#660000",
192
- "#783f04",
193
- "#7f6000",
194
- "#274e13",
195
- "#0c343d",
196
- "#1c4587",
192
+ "#783F04",
193
+ "#7F6000",
194
+ "#274E13",
195
+ "#0C343D",
196
+ "#1C4587",
197
197
  "#073763",
198
- "#20124d",
199
- "#4c1130",
198
+ "#20124D",
199
+ "#4C1130",
200
200
  ];
201
201
  // Dimensions
202
202
  const MIN_ROW_HEIGHT = 10;
@@ -234,7 +234,7 @@ const DEFAULT_FONT = "'Roboto', arial";
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
@@ -270,11 +270,13 @@ 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";
274
- ComponentsImportance[ComponentsImportance["Composer"] = 20] = "Composer";
273
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
274
+ ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
275
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
275
276
  ComponentsImportance[ComponentsImportance["ColorPicker"] = 25] = "ColorPicker";
276
277
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
277
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
278
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
279
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
278
280
  ComponentsImportance[ComponentsImportance["ChartAnchor"] = 1000] = "ChartAnchor";
279
281
  })(ComponentsImportance || (ComponentsImportance = {}));
280
282
  const DEFAULT_SHEETVIEW_SIZE = 1000;
@@ -1043,6 +1045,8 @@ function transpose2dArray(matrix) {
1043
1045
  return matrix[0].map((_, i) => matrix.map((row) => row[i]));
1044
1046
  }
1045
1047
 
1048
+ const RBA_REGEX = /rgba?\(|\s+|\)/gi;
1049
+ const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
1046
1050
  const colors$1 = [
1047
1051
  "#eb6d00",
1048
1052
  "#0074d9",
@@ -1073,7 +1077,10 @@ function getNextColor() {
1073
1077
  }
1074
1078
  /**
1075
1079
  * Converts any CSS color value to a standardized hex6 value.
1076
- * Accepts: hex3, hex6, hex8 and rgb (rgba is not supported)
1080
+ * Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
1081
+ *
1082
+ * [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
1083
+ * with r,g,b ∈ [0, 255] and a ∈ [0, 1]
1077
1084
  *
1078
1085
  * toHex("#ABC")
1079
1086
  * >> "#AABBCC"
@@ -1084,27 +1091,31 @@ function getNextColor() {
1084
1091
  * toHex("rgb(30, 80, 16)")
1085
1092
  * >> "#1E5010"
1086
1093
  *
1094
+ * * toHex("rgb(30, 80, 16, 0.5)")
1095
+ * >> "#1E501080"
1096
+ *
1087
1097
  */
1088
1098
  function toHex(color) {
1089
- if (color.includes("rgba")) {
1090
- throw new Error(`rgba() conversion currently not supported: ${color}`);
1099
+ let hexColor = color;
1100
+ if (color.startsWith("rgb")) {
1101
+ hexColor = rgbaStringToHex(color);
1091
1102
  }
1092
- if (color.includes("rgb")) {
1093
- return rgbToHex6(color);
1094
- }
1095
- color = color.replace("#", "").toUpperCase();
1096
- if (color.length === 3 || color.length === 4) {
1097
- color = color.split("").reduce((acc, h) => acc + h + h, "");
1103
+ else {
1104
+ hexColor = color.replace("#", "").toUpperCase();
1105
+ if (hexColor.length === 3 || hexColor.length === 4) {
1106
+ hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
1107
+ }
1108
+ hexColor = `#${hexColor}`;
1098
1109
  }
1099
- if (color.replace(/[a-f0-9]/gi, "") !== "") {
1100
- throw new Error("invalid color");
1110
+ if (!hexColor.match(HEX_MATCH)) {
1111
+ throw new Error(`invalid color input: ${color}`);
1101
1112
  }
1102
- return "#" + color;
1113
+ return hexColor;
1103
1114
  }
1104
1115
  function isColorValid(color) {
1105
1116
  try {
1106
- const { r, g, b, a } = colorToRGBA(color);
1107
- return (isColorValueValid(r) && isColorValueValid(g) && isColorValueValid(b) && isColorValueValid(a));
1117
+ toHex(color);
1118
+ return true;
1108
1119
  }
1109
1120
  catch (error) {
1110
1121
  return false;
@@ -1137,15 +1148,29 @@ function relativeLuminance(color) {
1137
1148
  /**
1138
1149
  * Convert a CSS rgb color string to a standardized hex6 color value.
1139
1150
  *
1140
- * rgbToHex6("rgb(30, 80, 16)")
1151
+ * rgbaStringToHex("rgb(30, 80, 16)")
1141
1152
  * >> "#1E5010"
1153
+ *
1154
+ * rgbaStringToHex("rgba(30, 80, 16, 0.5)")
1155
+ * >> "#1E501080"
1156
+ *
1157
+ * DOES NOT SUPPORT NON INTEGER RGB VALUES
1142
1158
  */
1143
- function rgbToHex6(color) {
1144
- return ("#" +
1145
- concat(color
1146
- .slice(4, -1)
1147
- .split(",")
1148
- .map((valueString) => parseInt(valueString, 10).toString(16).padStart(2, "0"))).toUpperCase());
1159
+ function rgbaStringToHex(color) {
1160
+ const stringVals = color.replace(RBA_REGEX, "").split(",");
1161
+ let alphaHex = 255;
1162
+ if (stringVals.length !== 3 && stringVals.length !== 4) {
1163
+ throw new Error("invalid color");
1164
+ }
1165
+ else if (stringVals.length === 4) {
1166
+ const alpha = parseFloat(stringVals.pop() || "1");
1167
+ alphaHex = Math.round((alpha || 1) * 255);
1168
+ }
1169
+ const vals = stringVals.map((val) => parseInt(val, 10));
1170
+ if (alphaHex !== 255) {
1171
+ vals.push(alphaHex);
1172
+ }
1173
+ return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
1149
1174
  }
1150
1175
  /**
1151
1176
  * RGBA to HEX representation (#RRGGBBAA).
@@ -1167,7 +1192,7 @@ function rgbaToHex(rgba) {
1167
1192
  a = "0" + a;
1168
1193
  if (a === "ff")
1169
1194
  a = "";
1170
- return "#" + r + g + b + a;
1195
+ return ("#" + r + g + b + a).toUpperCase();
1171
1196
  }
1172
1197
  /**
1173
1198
  * Color string to RGBA representation
@@ -1288,6 +1313,9 @@ function rgbaToHSLA(rgba) {
1288
1313
  s = +(s * 100).toFixed(1);
1289
1314
  l = +(l * 100).toFixed(1);
1290
1315
  return { a: rgba.a, h, s, l };
1316
+ }
1317
+ function isSameColor(color1, color2) {
1318
+ return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
1291
1319
  }
1292
1320
 
1293
1321
  /** Reference of a cell (eg. A1, $B$5) */
@@ -1846,7 +1874,7 @@ function convertInternalFormatToFormat(internalFormat) {
1846
1874
  * formula, commas are used to separate arguments
1847
1875
  * - it does not support % symbol, in formulas % is an operator
1848
1876
  */
1849
- const formulaNumberRegexp = /^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+/;
1877
+ const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
1850
1878
  const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
1851
1879
  const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
1852
1880
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -3826,7 +3854,7 @@ class Popover extends owl.Component {
3826
3854
  const shadow = maxHeight !== 0 ? "box-shadow: 1px 2px 5px 2px rgb(51 51 51 / 15%);" : "";
3827
3855
  return `
3828
3856
  position: absolute;
3829
- z-index: ${ComponentsImportance.Popover};
3857
+ z-index: ${this.props.zIndex};
3830
3858
  ${verticalPosition}px;
3831
3859
  ${horizontalPosition}px;
3832
3860
  ${height}px;
@@ -3870,6 +3898,7 @@ Popover.defaultProps = {
3870
3898
  verticalOffset: 0,
3871
3899
  marginTop: 0,
3872
3900
  onMouseWheel: () => { },
3901
+ zIndex: ComponentsImportance.Popover,
3873
3902
  };
3874
3903
 
3875
3904
  //------------------------------------------------------------------------------
@@ -8432,6 +8461,9 @@ class ColorPicker extends owl.Component {
8432
8461
  const { display, background, left, top } = this.state.style;
8433
8462
  return `display:${display};${display === "block" ? `background-color:${background};left:${left};top:${top};` : ""}`;
8434
8463
  }
8464
+ isSameColor(color1, color2) {
8465
+ return isSameColor(color1, color2);
8466
+ }
8435
8467
  }
8436
8468
  ColorPicker.template = "o-spreadsheet-ColorPicker";
8437
8469
 
@@ -8557,6 +8589,12 @@ class GaugeChartDesignPanel extends owl.Component {
8557
8589
  const cancelledReasons = [...(((_a = this.state.sectionRuleDispatchResult) === null || _a === void 0 ? void 0 : _a.reasons) || [])];
8558
8590
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
8559
8591
  }
8592
+ onClick(ev) {
8593
+ this.state.openedMenu = undefined;
8594
+ }
8595
+ setup() {
8596
+ owl.useExternalListener(window, "click", this.onClick);
8597
+ }
8560
8598
  updateBackgroundColor(color) {
8561
8599
  this.state.openedMenu = undefined;
8562
8600
  this.props.updateChart({
@@ -8725,6 +8763,12 @@ class ScorecardChartDesignPanel extends owl.Component {
8725
8763
  openedColorPicker: undefined,
8726
8764
  });
8727
8765
  }
8766
+ onClick(ev) {
8767
+ this.state.openedColorPicker = undefined;
8768
+ }
8769
+ setup() {
8770
+ owl.useExternalListener(window, "click", this.onClick);
8771
+ }
8728
8772
  updateTitle(ev) {
8729
8773
  this.props.updateChart({
8730
8774
  title: ev.target.value,
@@ -9963,6 +10007,7 @@ const CHART_PADDING_RATIO = 0.02;
9963
10007
  const LINE_HEIGHT = 1.2;
9964
10008
  css /* scss */ `
9965
10009
  div.o-scorecard {
10010
+ font-family: ${DEFAULT_FONT};
9966
10011
  user-select: none;
9967
10012
  background-color: white;
9968
10013
  display: flex;
@@ -19372,6 +19417,7 @@ class EditionPlugin extends UIPlugin {
19372
19417
  this.setContent(this.initialContent || "");
19373
19418
  }
19374
19419
  setContent(text, selection, raise) {
19420
+ text = text.replace(/[\r\n]/g, "");
19375
19421
  const isNewCurrentContent = this.currentContent !== text;
19376
19422
  this.currentContent = text;
19377
19423
  if (selection) {
@@ -19701,6 +19747,8 @@ class ContentEditableHelper {
19701
19747
  start = 0;
19702
19748
  if (end > this.el.textContent.length)
19703
19749
  end = this.el.textContent.length;
19750
+ if (start > this.el.textContent.length)
19751
+ start = this.el.textContent.length;
19704
19752
  }
19705
19753
  let startNode = this.findChildAtCharacterIndex(start);
19706
19754
  let endNode = this.findChildAtCharacterIndex(end);
@@ -19922,10 +19970,10 @@ css /* scss */ `
19922
19970
  padding: 0;
19923
19971
  margin: 0;
19924
19972
  border: 0;
19925
- z-index: ${ComponentsImportance.Composer};
19926
19973
  flex-grow: 1;
19927
19974
  max-height: inherit;
19928
19975
  .o-composer {
19976
+ font-family: ${DEFAULT_FONT};
19929
19977
  caret-color: black;
19930
19978
  padding-left: 3px;
19931
19979
  padding-right: 3px;
@@ -19955,6 +20003,10 @@ css /* scss */ `
19955
20003
  .o-topbar-toolbar .o-composer-container:focus-within {
19956
20004
  border: 1px solid ${SELECTION_BORDER_COLOR};
19957
20005
  }
20006
+
20007
+ .o-topbar-toolbar .o-composer-container {
20008
+ z-index: ${ComponentsImportance.TopBarComposer};
20009
+ }
19958
20010
  `;
19959
20011
  class Composer extends owl.Component {
19960
20012
  constructor() {
@@ -20379,7 +20431,7 @@ const SCROLLBAR_HIGHT = 15;
20379
20431
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
20380
20432
  css /* scss */ `
20381
20433
  div.o-grid-composer {
20382
- z-index: ${ComponentsImportance.Composer};
20434
+ z-index: ${ComponentsImportance.GridComposer};
20383
20435
  box-sizing: border-box;
20384
20436
  position: absolute;
20385
20437
  border: ${COMPOSER_BORDER_WIDTH}px solid ${SELECTION_BORDER_COLOR};
@@ -21209,6 +21261,10 @@ GridOverlay.defaultProps = {
21209
21261
  };
21210
21262
 
21211
21263
  class GridPopover extends owl.Component {
21264
+ constructor() {
21265
+ super(...arguments);
21266
+ this.zIndex = ComponentsImportance.GridPopover;
21267
+ }
21212
21268
  get cellPopover() {
21213
21269
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
21214
21270
  if (!popover.isOpen) {
@@ -22512,6 +22568,10 @@ class Grid extends owl.Component {
22512
22568
  }
22513
22569
  }
22514
22570
  onInput(ev) {
22571
+ // the user meant to paste in the sheet, not open the composer with the pasted content
22572
+ if (!ev.isComposing && ev.inputType === "insertFromPaste") {
22573
+ return;
22574
+ }
22515
22575
  if (ev.data) {
22516
22576
  // if the user types a character on the grid, it means he wants to start composing the selected cell with that
22517
22577
  // character
@@ -23727,6 +23787,72 @@ function fixXlsxUnicode(str) {
23727
23787
  });
23728
23788
  }
23729
23789
 
23790
+ 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;
23791
+ /**
23792
+ * Convert excel format to o_spreadsheet format
23793
+ *
23794
+ * Excel format are defined in openXML §18.8.31
23795
+ */
23796
+ function convertXlsxFormat(numFmtId, formats, warningManager) {
23797
+ var _a, _b, _c;
23798
+ if (numFmtId === 0) {
23799
+ return undefined;
23800
+ }
23801
+ // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23802
+ let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23803
+ if (format) {
23804
+ try {
23805
+ let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23806
+ convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23807
+ convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23808
+ // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23809
+ const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23810
+ const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23811
+ if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23812
+ throw new Error("Multiple escaped blocks in format");
23813
+ }
23814
+ convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23815
+ convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
23816
+ convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23817
+ convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23818
+ convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
23819
+ if (isXlsxDateFormat(convertedFormat)) {
23820
+ convertedFormat = convertDateFormat$1(convertedFormat);
23821
+ }
23822
+ if (isFormatSupported(convertedFormat)) {
23823
+ return convertedFormat;
23824
+ }
23825
+ }
23826
+ catch (e) { }
23827
+ }
23828
+ warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23829
+ return undefined;
23830
+ }
23831
+ function isFormatSupported(format) {
23832
+ try {
23833
+ formatValue(0, format);
23834
+ return true;
23835
+ }
23836
+ catch (e) {
23837
+ return false;
23838
+ }
23839
+ }
23840
+ function isXlsxDateFormat(format) {
23841
+ return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
23842
+ }
23843
+ function convertDateFormat$1(format) {
23844
+ // Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
23845
+ // but can still occur and are supported by Excel/Google sheets
23846
+ format = format.toLowerCase();
23847
+ format = format.replace(/mmmmm|mmmm|mmm/g, "mm");
23848
+ format = format.replace(/dddd|ddd/g, "dd");
23849
+ format = format.replace(/am\/pm|a\/m/g, "a");
23850
+ format = format.replace(/\byy\b/g, "yyyy");
23851
+ format = format.replace(/hhhh/g, "hh");
23852
+ format = format.replace(/\bh\b/g, "hh");
23853
+ return format;
23854
+ }
23855
+
23730
23856
  function convertBorders(data, warningManager) {
23731
23857
  const borderArray = data.borders.map((border) => {
23732
23858
  addBorderWarnings(border, warningManager);
@@ -23791,41 +23917,6 @@ function convertFormats(data, warningManager) {
23791
23917
  }
23792
23918
  return arrayToObject(formats, 1);
23793
23919
  }
23794
- /**
23795
- * Convert excel format to o_spreadsheet format
23796
- *
23797
- * Excel format are defined in openXML §18.8.31
23798
- */
23799
- function convertXlsxFormat(numFmtId, formats, warningManager) {
23800
- var _a, _b, _c;
23801
- if (numFmtId === 0) {
23802
- return undefined;
23803
- }
23804
- // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23805
- let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23806
- if (format) {
23807
- try {
23808
- let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23809
- convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23810
- convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23811
- // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23812
- const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23813
- const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23814
- if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23815
- throw new Error("Multiple escaped blocks in format");
23816
- }
23817
- convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23818
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
23819
- convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23820
- convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23821
- formatValue(0, convertedFormat);
23822
- return convertedFormat;
23823
- }
23824
- catch (e) { }
23825
- }
23826
- warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23827
- return undefined;
23828
- }
23829
23920
  /**
23830
23921
  * We currently only support only a set of font sizes, we cannot define new font sizes.
23831
23922
  * This function adapts an arbitrary font size to the closest supported font size.
@@ -32008,9 +32099,7 @@ class CustomColorsPlugin extends UIPlugin {
32008
32099
  // remove duplicates first to check validity on a reduced
32009
32100
  // set of colors, then normalize to HEX and remove duplicates
32010
32101
  // again
32011
- [...new Set([...usedColors, ...this.customColors])]
32012
- .filter(isColorValid)
32013
- .map((c) => toHex(c).toLowerCase())),
32102
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
32014
32103
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
32015
32104
  }
32016
32105
  getColorsFromCells(cells) {
@@ -32071,7 +32160,7 @@ class CustomColorsPlugin extends UIPlugin {
32071
32160
  return [...chartsColors];
32072
32161
  }
32073
32162
  tryToAddColor(color) {
32074
- const formattedColor = toHex(color).toLowerCase();
32163
+ const formattedColor = toHex(color);
32075
32164
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
32076
32165
  this.customColors.add(formattedColor);
32077
32166
  }
@@ -35812,8 +35901,8 @@ class InternalViewport {
35812
35901
  this.getters = getters;
35813
35902
  this.sheetId = sheetId;
35814
35903
  this.boundaries = boundaries;
35815
- this.width = sizeInGrid.width;
35816
- this.height = sizeInGrid.height;
35904
+ this.viewportWidth = sizeInGrid.width;
35905
+ this.viewportHeight = sizeInGrid.height;
35817
35906
  this.offsetScrollbarX = offsets.x;
35818
35907
  this.offsetScrollbarY = offsets.y;
35819
35908
  this.canScrollVertically = options.canScrollVertically;
@@ -35824,6 +35913,10 @@ class InternalViewport {
35824
35913
  this.adjustViewportOffsetY();
35825
35914
  }
35826
35915
  // PUBLIC
35916
+ /** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
35917
+ * When the viewport grid size is smaller than its client width (resp. height), it will return
35918
+ * the client width (resp. height).
35919
+ */
35827
35920
  getMaxSize() {
35828
35921
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
35829
35922
  first: this.boundaries.left,
@@ -35835,20 +35928,24 @@ class InternalViewport {
35835
35928
  });
35836
35929
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
35837
35930
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
35838
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
35931
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
35839
35932
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
35840
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
35933
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
35841
35934
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
35842
- const width = lastColEnd -
35843
- this.offsetCorrectionX +
35844
- (this.canScrollHorizontally
35845
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
35846
- : 0);
35847
- const height = lastRowEnd -
35848
- this.offsetCorrectionY +
35849
- (this.canScrollVertically
35850
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
35851
- : 0);
35935
+ let width = lastColEnd - this.offsetCorrectionX;
35936
+ if (this.canScrollHorizontally) {
35937
+ width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
35938
+ Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
35939
+ );
35940
+ width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
35941
+ }
35942
+ let height = lastRowEnd - this.offsetCorrectionY;
35943
+ if (this.canScrollVertically) {
35944
+ height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
35945
+ Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
35946
+ );
35947
+ height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
35948
+ }
35852
35949
  return { width, height };
35853
35950
  }
35854
35951
  /**
@@ -35857,7 +35954,7 @@ class InternalViewport {
35857
35954
  * It returns -1 if no column is found.
35858
35955
  */
35859
35956
  getColIndex(x, absolute = false) {
35860
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
35957
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
35861
35958
  return -1;
35862
35959
  }
35863
35960
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -35868,7 +35965,7 @@ class InternalViewport {
35868
35965
  * It returns -1 if no row is found.
35869
35966
  */
35870
35967
  getRowIndex(y, absolute = false) {
35871
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
35968
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
35872
35969
  return -1;
35873
35970
  }
35874
35971
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -35895,7 +35992,7 @@ class InternalViewport {
35895
35992
  adjustPositionX(col) {
35896
35993
  const sheetId = this.sheetId;
35897
35994
  const { start, end } = this.getters.getColDimensions(sheetId, col);
35898
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
35995
+ while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
35899
35996
  this.offsetX + this.offsetCorrectionX < start) {
35900
35997
  this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
35901
35998
  this.offsetScrollbarX = this.offsetX;
@@ -35917,7 +36014,7 @@ class InternalViewport {
35917
36014
  adjustPositionY(row) {
35918
36015
  const sheetId = this.sheetId;
35919
36016
  while (this.getters.getRowDimensions(sheetId, row).end >
35920
- this.offsetY + this.height + this.offsetCorrectionY &&
36017
+ this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
35921
36018
  this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
35922
36019
  this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
35923
36020
  this.offsetScrollbarY = this.offsetY;
@@ -35955,8 +36052,8 @@ class InternalViewport {
35955
36052
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
35956
36053
  this.offsetCorrectionX;
35957
36054
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
35958
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
35959
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
36055
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
36056
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
35960
36057
  return {
35961
36058
  x,
35962
36059
  y,
@@ -36019,12 +36116,12 @@ class InternalViewport {
36019
36116
  adjustViewportOffsetX() {
36020
36117
  if (this.canScrollHorizontally) {
36021
36118
  const { width: viewportWidth } = this.getMaxSize();
36022
- if (this.width + this.offsetScrollbarX > viewportWidth) {
36023
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
36119
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
36120
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
36024
36121
  }
36025
36122
  }
36026
36123
  this.left = this.getColIndex(this.offsetScrollbarX, true);
36027
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
36124
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
36028
36125
  if (this.right === -1) {
36029
36126
  this.right = this.boundaries.right;
36030
36127
  }
@@ -36036,12 +36133,12 @@ class InternalViewport {
36036
36133
  adjustViewportOffsetY() {
36037
36134
  if (this.canScrollVertically) {
36038
36135
  const { height: paneHeight } = this.getMaxSize();
36039
- if (this.height + this.offsetScrollbarY > paneHeight) {
36040
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
36136
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
36137
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
36041
36138
  }
36042
36139
  }
36043
36140
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
36044
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
36141
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
36045
36142
  if (this.bottom === -1) {
36046
36143
  this.bottom = this.boundaries.bottom;
36047
36144
  }
@@ -36052,7 +36149,7 @@ class InternalViewport {
36052
36149
  adjustViewportZoneX() {
36053
36150
  const sheetId = this.sheetId;
36054
36151
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
36055
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
36152
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
36056
36153
  if (this.right === -1) {
36057
36154
  this.right = this.getters.getNumberCols(sheetId) - 1;
36058
36155
  }
@@ -36065,7 +36162,7 @@ class InternalViewport {
36065
36162
  adjustViewportZoneY() {
36066
36163
  const sheetId = this.sheetId;
36067
36164
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
36068
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
36165
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
36069
36166
  if (this.bottom === -1) {
36070
36167
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
36071
36168
  }
@@ -36324,8 +36421,7 @@ class SheetViewPlugin extends UIPlugin {
36324
36421
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
36325
36422
  }
36326
36423
  /**
36327
- * Return the main viewport maximum size. That is the zone dimension
36328
- * with some bottom and right padding.
36424
+ * Return the main viewport maximum size relative to the client size.
36329
36425
  */
36330
36426
  getMainViewportRect() {
36331
36427
  const sheetId = this.getters.getActiveSheetId();
@@ -36341,8 +36437,8 @@ class SheetViewPlugin extends UIPlugin {
36341
36437
  const { width, height } = this.getMainViewportRect();
36342
36438
  const viewport = this.getMainInternalViewport(sheetId);
36343
36439
  return {
36344
- maxOffsetX: Math.max(0, width - viewport.width + 1),
36345
- maxOffsetY: Math.max(0, height - viewport.height + 1),
36440
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
36441
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
36346
36442
  };
36347
36443
  }
36348
36444
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -38359,9 +38455,6 @@ css /* scss */ `
38359
38455
  color: #333;
38360
38456
  }
38361
38457
 
38362
- * {
38363
- font-family: "Roboto", "RobotoDraft", Helvetica, Arial, sans-serif;
38364
- }
38365
38458
  &,
38366
38459
  *,
38367
38460
  *:before,
@@ -39537,6 +39630,7 @@ class RangeAdapter {
39537
39630
  }
39538
39631
  else if (range.zone[start] >= min && range.zone[end] <= max) {
39539
39632
  changeType = "REMOVE";
39633
+ newRange = range.clone({ ...this.getInvalidRange() });
39540
39634
  }
39541
39635
  else if (range.zone[start] <= max && range.zone[end] >= max) {
39542
39636
  const toRemove = max - range.zone[start] + 1;
@@ -39602,8 +39696,10 @@ class RangeAdapter {
39602
39696
  return { changeType: "NONE" };
39603
39697
  }
39604
39698
  const invalidSheetName = this.getters.getSheetName(cmd.sheetId);
39605
- const sheetId = "";
39606
- range = range.clone({ sheetId, invalidSheetName });
39699
+ range = range.clone({
39700
+ ...this.getInvalidRange(),
39701
+ invalidSheetName,
39702
+ });
39607
39703
  return { changeType: "REMOVE", range };
39608
39704
  }, cmd.sheetId);
39609
39705
  break;
@@ -39867,6 +39963,15 @@ class RangeAdapter {
39867
39963
  }
39868
39964
  return str;
39869
39965
  }
39966
+ getInvalidRange() {
39967
+ return {
39968
+ parts: [],
39969
+ prefixSheet: false,
39970
+ zone: { left: -1, top: -1, right: -1, bottom: -1 },
39971
+ sheetId: "",
39972
+ invalidXc: INCORRECT_RANGE_STRING,
39973
+ };
39974
+ }
39870
39975
  }
39871
39976
  RangeAdapter.getters = [
39872
39977
  "getRangeString",
@@ -42471,6 +42576,6 @@ exports.setTranslationMethod = setTranslationMethod;
42471
42576
  exports.tokenize = tokenize;
42472
42577
 
42473
42578
 
42474
- __info__.version = '16.0.4';
42475
- __info__.date = '2023-03-16T12:11:01.007Z';
42476
- __info__.hash = 'ebbb1f0';
42579
+ __info__.version = '16.0.6';
42580
+ __info__.date = '2023-04-13T08:30:26.954Z';
42581
+ __info__.hash = '8d60b5c';