@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.
@@ -111,88 +111,88 @@ const LINK_COLOR = "#01666b";
111
111
  const FILTERS_COLOR = "#188038";
112
112
  const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
113
113
  const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
114
- // Color picker
114
+ // Color picker defaults as upper case HEX to match `toHex`helper
115
115
  const COLOR_PICKER_DEFAULTS = [
116
116
  "#000000",
117
117
  "#434343",
118
118
  "#666666",
119
119
  "#999999",
120
- "#b7b7b7",
121
- "#cccccc",
122
- "#d9d9d9",
123
- "#efefef",
124
- "#f3f3f3",
125
- "#ffffff",
120
+ "#B7B7B7",
121
+ "#CCCCCC",
122
+ "#D9D9D9",
123
+ "#EFEFEF",
124
+ "#F3F3F3",
125
+ "#FFFFFF",
126
126
  "#980000",
127
- "#ff0000",
128
- "#ff9900",
129
- "#ffff00",
130
- "#00ff00",
131
- "#00ffff",
132
- "#4a86e8",
133
- "#0000ff",
134
- "#9900ff",
135
- "#ff00ff",
136
- "#e6b8af",
137
- "#f4cccc",
138
- "#fce5cd",
139
- "#fff2cc",
140
- "#d9ead3",
141
- "#d0e0e3",
142
- "#c9daf8",
143
- "#cfe2f3",
144
- "#d9d2e9",
145
- "#ead1dc",
146
- "#dd7e6b",
147
- "#ea9999",
148
- "#f9cb9c",
149
- "#ffe599",
150
- "#b6d7a8",
151
- "#a2c4c9",
152
- "#a4c2f4",
153
- "#9fc5e8",
154
- "#b4a7d6",
155
- "#d5a6bd",
156
- "#cc4125",
157
- "#e06666",
158
- "#f6b26b",
159
- "#ffd966",
160
- "#93c47d",
161
- "#76a5af",
162
- "#6d9eeb",
163
- "#6fa8dc",
164
- "#8e7cc3",
165
- "#c27ba0",
166
- "#a61c00",
167
- "#cc0000",
168
- "#e69138",
169
- "#f1c232",
170
- "#6aa84f",
171
- "#45818e",
172
- "#3c78d8",
173
- "#3d85c6",
174
- "#674ea7",
175
- "#a64d79",
176
- "#85200c",
127
+ "#FF0000",
128
+ "#FF9900",
129
+ "#FFFF00",
130
+ "#00FF00",
131
+ "#00FFFF",
132
+ "#4A86E8",
133
+ "#0000FF",
134
+ "#9900FF",
135
+ "#FF00FF",
136
+ "#E6B8AF",
137
+ "#F4CCCC",
138
+ "#FCE5CD",
139
+ "#FFF2CC",
140
+ "#D9EAD3",
141
+ "#D0E0E3",
142
+ "#C9DAF8",
143
+ "#CFE2F3",
144
+ "#D9D2E9",
145
+ "#EAD1DC",
146
+ "#DD7E6B",
147
+ "#EA9999",
148
+ "#F9CB9C",
149
+ "#FFE599",
150
+ "#B6D7A8",
151
+ "#A2C4C9",
152
+ "#A4C2F4",
153
+ "#9FC5E8",
154
+ "#B4A7D6",
155
+ "#D5A6BD",
156
+ "#CC4125",
157
+ "#E06666",
158
+ "#F6B26B",
159
+ "#FFD966",
160
+ "#93C47D",
161
+ "#76A5AF",
162
+ "#6D9EEB",
163
+ "#6FA8DC",
164
+ "#8E7CC3",
165
+ "#C27BA0",
166
+ "#A61C00",
167
+ "#CC0000",
168
+ "#E69138",
169
+ "#F1C232",
170
+ "#6AA84F",
171
+ "#45818E",
172
+ "#3C78D8",
173
+ "#3D85C6",
174
+ "#674EA7",
175
+ "#A64D79",
176
+ "#85200C",
177
177
  "#990000",
178
- "#b45f06",
179
- "#bf9000",
180
- "#38761d",
181
- "#134f5c",
182
- "#1155cc",
183
- "#0b5394",
184
- "#351c75",
185
- "#741b47",
186
- "#5b0f00",
178
+ "#B45F06",
179
+ "#BF9000",
180
+ "#38761D",
181
+ "#134F5C",
182
+ "#1155CC",
183
+ "#0B5394",
184
+ "#351C75",
185
+ "#741B47",
186
+ "#5B0F00",
187
187
  "#660000",
188
- "#783f04",
189
- "#7f6000",
190
- "#274e13",
191
- "#0c343d",
192
- "#1c4587",
188
+ "#783F04",
189
+ "#7F6000",
190
+ "#274E13",
191
+ "#0C343D",
192
+ "#1C4587",
193
193
  "#073763",
194
- "#20124d",
195
- "#4c1130",
194
+ "#20124D",
195
+ "#4C1130",
196
196
  ];
197
197
  // Dimensions
198
198
  const MIN_ROW_HEIGHT = 10;
@@ -230,7 +230,7 @@ const DEFAULT_FONT = "'Roboto', arial";
230
230
  const DEFAULT_BORDER_DESC = ["thin", "#000"];
231
231
  const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
232
232
  // DateTimeRegex
233
- const DATETIME_FORMAT = /[ymd:]/;
233
+ const DATETIME_FORMAT = /[ymdhs:]/;
234
234
  // Ranges
235
235
  const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
236
236
  // Max Number of history steps kept in memory
@@ -266,11 +266,13 @@ var ComponentsImportance;
266
266
  ComponentsImportance[ComponentsImportance["Highlight"] = 5] = "Highlight";
267
267
  ComponentsImportance[ComponentsImportance["Figure"] = 10] = "Figure";
268
268
  ComponentsImportance[ComponentsImportance["ScrollBar"] = 15] = "ScrollBar";
269
- ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
270
- ComponentsImportance[ComponentsImportance["Composer"] = 20] = "Composer";
269
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
270
+ ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
271
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
271
272
  ComponentsImportance[ComponentsImportance["ColorPicker"] = 25] = "ColorPicker";
272
273
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
273
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
274
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
275
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
274
276
  ComponentsImportance[ComponentsImportance["ChartAnchor"] = 1000] = "ChartAnchor";
275
277
  })(ComponentsImportance || (ComponentsImportance = {}));
276
278
  const DEFAULT_SHEETVIEW_SIZE = 1000;
@@ -1039,6 +1041,8 @@ function transpose2dArray(matrix) {
1039
1041
  return matrix[0].map((_, i) => matrix.map((row) => row[i]));
1040
1042
  }
1041
1043
 
1044
+ const RBA_REGEX = /rgba?\(|\s+|\)/gi;
1045
+ const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
1042
1046
  const colors$1 = [
1043
1047
  "#eb6d00",
1044
1048
  "#0074d9",
@@ -1069,7 +1073,10 @@ function getNextColor() {
1069
1073
  }
1070
1074
  /**
1071
1075
  * Converts any CSS color value to a standardized hex6 value.
1072
- * Accepts: hex3, hex6, hex8 and rgb (rgba is not supported)
1076
+ * Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
1077
+ *
1078
+ * [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
1079
+ * with r,g,b ∈ [0, 255] and a ∈ [0, 1]
1073
1080
  *
1074
1081
  * toHex("#ABC")
1075
1082
  * >> "#AABBCC"
@@ -1080,27 +1087,31 @@ function getNextColor() {
1080
1087
  * toHex("rgb(30, 80, 16)")
1081
1088
  * >> "#1E5010"
1082
1089
  *
1090
+ * * toHex("rgb(30, 80, 16, 0.5)")
1091
+ * >> "#1E501080"
1092
+ *
1083
1093
  */
1084
1094
  function toHex(color) {
1085
- if (color.includes("rgba")) {
1086
- throw new Error(`rgba() conversion currently not supported: ${color}`);
1095
+ let hexColor = color;
1096
+ if (color.startsWith("rgb")) {
1097
+ hexColor = rgbaStringToHex(color);
1087
1098
  }
1088
- if (color.includes("rgb")) {
1089
- return rgbToHex6(color);
1090
- }
1091
- color = color.replace("#", "").toUpperCase();
1092
- if (color.length === 3 || color.length === 4) {
1093
- color = color.split("").reduce((acc, h) => acc + h + h, "");
1099
+ else {
1100
+ hexColor = color.replace("#", "").toUpperCase();
1101
+ if (hexColor.length === 3 || hexColor.length === 4) {
1102
+ hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
1103
+ }
1104
+ hexColor = `#${hexColor}`;
1094
1105
  }
1095
- if (color.replace(/[a-f0-9]/gi, "") !== "") {
1096
- throw new Error("invalid color");
1106
+ if (!hexColor.match(HEX_MATCH)) {
1107
+ throw new Error(`invalid color input: ${color}`);
1097
1108
  }
1098
- return "#" + color;
1109
+ return hexColor;
1099
1110
  }
1100
1111
  function isColorValid(color) {
1101
1112
  try {
1102
- const { r, g, b, a } = colorToRGBA(color);
1103
- return (isColorValueValid(r) && isColorValueValid(g) && isColorValueValid(b) && isColorValueValid(a));
1113
+ toHex(color);
1114
+ return true;
1104
1115
  }
1105
1116
  catch (error) {
1106
1117
  return false;
@@ -1133,15 +1144,29 @@ function relativeLuminance(color) {
1133
1144
  /**
1134
1145
  * Convert a CSS rgb color string to a standardized hex6 color value.
1135
1146
  *
1136
- * rgbToHex6("rgb(30, 80, 16)")
1147
+ * rgbaStringToHex("rgb(30, 80, 16)")
1137
1148
  * >> "#1E5010"
1149
+ *
1150
+ * rgbaStringToHex("rgba(30, 80, 16, 0.5)")
1151
+ * >> "#1E501080"
1152
+ *
1153
+ * DOES NOT SUPPORT NON INTEGER RGB VALUES
1138
1154
  */
1139
- function rgbToHex6(color) {
1140
- return ("#" +
1141
- concat(color
1142
- .slice(4, -1)
1143
- .split(",")
1144
- .map((valueString) => parseInt(valueString, 10).toString(16).padStart(2, "0"))).toUpperCase());
1155
+ function rgbaStringToHex(color) {
1156
+ const stringVals = color.replace(RBA_REGEX, "").split(",");
1157
+ let alphaHex = 255;
1158
+ if (stringVals.length !== 3 && stringVals.length !== 4) {
1159
+ throw new Error("invalid color");
1160
+ }
1161
+ else if (stringVals.length === 4) {
1162
+ const alpha = parseFloat(stringVals.pop() || "1");
1163
+ alphaHex = Math.round((alpha || 1) * 255);
1164
+ }
1165
+ const vals = stringVals.map((val) => parseInt(val, 10));
1166
+ if (alphaHex !== 255) {
1167
+ vals.push(alphaHex);
1168
+ }
1169
+ return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
1145
1170
  }
1146
1171
  /**
1147
1172
  * RGBA to HEX representation (#RRGGBBAA).
@@ -1163,7 +1188,7 @@ function rgbaToHex(rgba) {
1163
1188
  a = "0" + a;
1164
1189
  if (a === "ff")
1165
1190
  a = "";
1166
- return "#" + r + g + b + a;
1191
+ return ("#" + r + g + b + a).toUpperCase();
1167
1192
  }
1168
1193
  /**
1169
1194
  * Color string to RGBA representation
@@ -1284,6 +1309,9 @@ function rgbaToHSLA(rgba) {
1284
1309
  s = +(s * 100).toFixed(1);
1285
1310
  l = +(l * 100).toFixed(1);
1286
1311
  return { a: rgba.a, h, s, l };
1312
+ }
1313
+ function isSameColor(color1, color2) {
1314
+ return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
1287
1315
  }
1288
1316
 
1289
1317
  /** Reference of a cell (eg. A1, $B$5) */
@@ -1842,7 +1870,7 @@ function convertInternalFormatToFormat(internalFormat) {
1842
1870
  * formula, commas are used to separate arguments
1843
1871
  * - it does not support % symbol, in formulas % is an operator
1844
1872
  */
1845
- const formulaNumberRegexp = /^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+/;
1873
+ const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
1846
1874
  const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
1847
1875
  const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
1848
1876
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -3822,7 +3850,7 @@ class Popover extends Component {
3822
3850
  const shadow = maxHeight !== 0 ? "box-shadow: 1px 2px 5px 2px rgb(51 51 51 / 15%);" : "";
3823
3851
  return `
3824
3852
  position: absolute;
3825
- z-index: ${ComponentsImportance.Popover};
3853
+ z-index: ${this.props.zIndex};
3826
3854
  ${verticalPosition}px;
3827
3855
  ${horizontalPosition}px;
3828
3856
  ${height}px;
@@ -3866,6 +3894,7 @@ Popover.defaultProps = {
3866
3894
  verticalOffset: 0,
3867
3895
  marginTop: 0,
3868
3896
  onMouseWheel: () => { },
3897
+ zIndex: ComponentsImportance.Popover,
3869
3898
  };
3870
3899
 
3871
3900
  //------------------------------------------------------------------------------
@@ -8428,6 +8457,9 @@ class ColorPicker extends Component {
8428
8457
  const { display, background, left, top } = this.state.style;
8429
8458
  return `display:${display};${display === "block" ? `background-color:${background};left:${left};top:${top};` : ""}`;
8430
8459
  }
8460
+ isSameColor(color1, color2) {
8461
+ return isSameColor(color1, color2);
8462
+ }
8431
8463
  }
8432
8464
  ColorPicker.template = "o-spreadsheet-ColorPicker";
8433
8465
 
@@ -8553,6 +8585,12 @@ class GaugeChartDesignPanel extends Component {
8553
8585
  const cancelledReasons = [...(((_a = this.state.sectionRuleDispatchResult) === null || _a === void 0 ? void 0 : _a.reasons) || [])];
8554
8586
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
8555
8587
  }
8588
+ onClick(ev) {
8589
+ this.state.openedMenu = undefined;
8590
+ }
8591
+ setup() {
8592
+ useExternalListener(window, "click", this.onClick);
8593
+ }
8556
8594
  updateBackgroundColor(color) {
8557
8595
  this.state.openedMenu = undefined;
8558
8596
  this.props.updateChart({
@@ -8721,6 +8759,12 @@ class ScorecardChartDesignPanel extends Component {
8721
8759
  openedColorPicker: undefined,
8722
8760
  });
8723
8761
  }
8762
+ onClick(ev) {
8763
+ this.state.openedColorPicker = undefined;
8764
+ }
8765
+ setup() {
8766
+ useExternalListener(window, "click", this.onClick);
8767
+ }
8724
8768
  updateTitle(ev) {
8725
8769
  this.props.updateChart({
8726
8770
  title: ev.target.value,
@@ -9959,6 +10003,7 @@ const CHART_PADDING_RATIO = 0.02;
9959
10003
  const LINE_HEIGHT = 1.2;
9960
10004
  css /* scss */ `
9961
10005
  div.o-scorecard {
10006
+ font-family: ${DEFAULT_FONT};
9962
10007
  user-select: none;
9963
10008
  background-color: white;
9964
10009
  display: flex;
@@ -19368,6 +19413,7 @@ class EditionPlugin extends UIPlugin {
19368
19413
  this.setContent(this.initialContent || "");
19369
19414
  }
19370
19415
  setContent(text, selection, raise) {
19416
+ text = text.replace(/[\r\n]/g, "");
19371
19417
  const isNewCurrentContent = this.currentContent !== text;
19372
19418
  this.currentContent = text;
19373
19419
  if (selection) {
@@ -19697,6 +19743,8 @@ class ContentEditableHelper {
19697
19743
  start = 0;
19698
19744
  if (end > this.el.textContent.length)
19699
19745
  end = this.el.textContent.length;
19746
+ if (start > this.el.textContent.length)
19747
+ start = this.el.textContent.length;
19700
19748
  }
19701
19749
  let startNode = this.findChildAtCharacterIndex(start);
19702
19750
  let endNode = this.findChildAtCharacterIndex(end);
@@ -19918,10 +19966,10 @@ css /* scss */ `
19918
19966
  padding: 0;
19919
19967
  margin: 0;
19920
19968
  border: 0;
19921
- z-index: ${ComponentsImportance.Composer};
19922
19969
  flex-grow: 1;
19923
19970
  max-height: inherit;
19924
19971
  .o-composer {
19972
+ font-family: ${DEFAULT_FONT};
19925
19973
  caret-color: black;
19926
19974
  padding-left: 3px;
19927
19975
  padding-right: 3px;
@@ -19951,6 +19999,10 @@ css /* scss */ `
19951
19999
  .o-topbar-toolbar .o-composer-container:focus-within {
19952
20000
  border: 1px solid ${SELECTION_BORDER_COLOR};
19953
20001
  }
20002
+
20003
+ .o-topbar-toolbar .o-composer-container {
20004
+ z-index: ${ComponentsImportance.TopBarComposer};
20005
+ }
19954
20006
  `;
19955
20007
  class Composer extends Component {
19956
20008
  constructor() {
@@ -20375,7 +20427,7 @@ const SCROLLBAR_HIGHT = 15;
20375
20427
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
20376
20428
  css /* scss */ `
20377
20429
  div.o-grid-composer {
20378
- z-index: ${ComponentsImportance.Composer};
20430
+ z-index: ${ComponentsImportance.GridComposer};
20379
20431
  box-sizing: border-box;
20380
20432
  position: absolute;
20381
20433
  border: ${COMPOSER_BORDER_WIDTH}px solid ${SELECTION_BORDER_COLOR};
@@ -21205,6 +21257,10 @@ GridOverlay.defaultProps = {
21205
21257
  };
21206
21258
 
21207
21259
  class GridPopover extends Component {
21260
+ constructor() {
21261
+ super(...arguments);
21262
+ this.zIndex = ComponentsImportance.GridPopover;
21263
+ }
21208
21264
  get cellPopover() {
21209
21265
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
21210
21266
  if (!popover.isOpen) {
@@ -22508,6 +22564,10 @@ class Grid extends Component {
22508
22564
  }
22509
22565
  }
22510
22566
  onInput(ev) {
22567
+ // the user meant to paste in the sheet, not open the composer with the pasted content
22568
+ if (!ev.isComposing && ev.inputType === "insertFromPaste") {
22569
+ return;
22570
+ }
22511
22571
  if (ev.data) {
22512
22572
  // if the user types a character on the grid, it means he wants to start composing the selected cell with that
22513
22573
  // character
@@ -23723,6 +23783,72 @@ function fixXlsxUnicode(str) {
23723
23783
  });
23724
23784
  }
23725
23785
 
23786
+ const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
23787
+ /**
23788
+ * Convert excel format to o_spreadsheet format
23789
+ *
23790
+ * Excel format are defined in openXML §18.8.31
23791
+ */
23792
+ function convertXlsxFormat(numFmtId, formats, warningManager) {
23793
+ var _a, _b, _c;
23794
+ if (numFmtId === 0) {
23795
+ return undefined;
23796
+ }
23797
+ // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23798
+ let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23799
+ if (format) {
23800
+ try {
23801
+ let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23802
+ convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23803
+ convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23804
+ // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23805
+ const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23806
+ const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23807
+ if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23808
+ throw new Error("Multiple escaped blocks in format");
23809
+ }
23810
+ convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23811
+ convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
23812
+ convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23813
+ convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23814
+ convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
23815
+ if (isXlsxDateFormat(convertedFormat)) {
23816
+ convertedFormat = convertDateFormat$1(convertedFormat);
23817
+ }
23818
+ if (isFormatSupported(convertedFormat)) {
23819
+ return convertedFormat;
23820
+ }
23821
+ }
23822
+ catch (e) { }
23823
+ }
23824
+ warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23825
+ return undefined;
23826
+ }
23827
+ function isFormatSupported(format) {
23828
+ try {
23829
+ formatValue(0, format);
23830
+ return true;
23831
+ }
23832
+ catch (e) {
23833
+ return false;
23834
+ }
23835
+ }
23836
+ function isXlsxDateFormat(format) {
23837
+ return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
23838
+ }
23839
+ function convertDateFormat$1(format) {
23840
+ // Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
23841
+ // but can still occur and are supported by Excel/Google sheets
23842
+ format = format.toLowerCase();
23843
+ format = format.replace(/mmmmm|mmmm|mmm/g, "mm");
23844
+ format = format.replace(/dddd|ddd/g, "dd");
23845
+ format = format.replace(/am\/pm|a\/m/g, "a");
23846
+ format = format.replace(/\byy\b/g, "yyyy");
23847
+ format = format.replace(/hhhh/g, "hh");
23848
+ format = format.replace(/\bh\b/g, "hh");
23849
+ return format;
23850
+ }
23851
+
23726
23852
  function convertBorders(data, warningManager) {
23727
23853
  const borderArray = data.borders.map((border) => {
23728
23854
  addBorderWarnings(border, warningManager);
@@ -23787,41 +23913,6 @@ function convertFormats(data, warningManager) {
23787
23913
  }
23788
23914
  return arrayToObject(formats, 1);
23789
23915
  }
23790
- /**
23791
- * Convert excel format to o_spreadsheet format
23792
- *
23793
- * Excel format are defined in openXML §18.8.31
23794
- */
23795
- function convertXlsxFormat(numFmtId, formats, warningManager) {
23796
- var _a, _b, _c;
23797
- if (numFmtId === 0) {
23798
- return undefined;
23799
- }
23800
- // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
23801
- let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
23802
- if (format) {
23803
- try {
23804
- let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
23805
- convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
23806
- convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
23807
- // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
23808
- const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
23809
- const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
23810
- if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
23811
- throw new Error("Multiple escaped blocks in format");
23812
- }
23813
- convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23814
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
23815
- convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23816
- convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23817
- formatValue(0, convertedFormat);
23818
- return convertedFormat;
23819
- }
23820
- catch (e) { }
23821
- }
23822
- warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23823
- return undefined;
23824
- }
23825
23916
  /**
23826
23917
  * We currently only support only a set of font sizes, we cannot define new font sizes.
23827
23918
  * This function adapts an arbitrary font size to the closest supported font size.
@@ -32004,9 +32095,7 @@ class CustomColorsPlugin extends UIPlugin {
32004
32095
  // remove duplicates first to check validity on a reduced
32005
32096
  // set of colors, then normalize to HEX and remove duplicates
32006
32097
  // again
32007
- [...new Set([...usedColors, ...this.customColors])]
32008
- .filter(isColorValid)
32009
- .map((c) => toHex(c).toLowerCase())),
32098
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
32010
32099
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
32011
32100
  }
32012
32101
  getColorsFromCells(cells) {
@@ -32067,7 +32156,7 @@ class CustomColorsPlugin extends UIPlugin {
32067
32156
  return [...chartsColors];
32068
32157
  }
32069
32158
  tryToAddColor(color) {
32070
- const formattedColor = toHex(color).toLowerCase();
32159
+ const formattedColor = toHex(color);
32071
32160
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
32072
32161
  this.customColors.add(formattedColor);
32073
32162
  }
@@ -35808,8 +35897,8 @@ class InternalViewport {
35808
35897
  this.getters = getters;
35809
35898
  this.sheetId = sheetId;
35810
35899
  this.boundaries = boundaries;
35811
- this.width = sizeInGrid.width;
35812
- this.height = sizeInGrid.height;
35900
+ this.viewportWidth = sizeInGrid.width;
35901
+ this.viewportHeight = sizeInGrid.height;
35813
35902
  this.offsetScrollbarX = offsets.x;
35814
35903
  this.offsetScrollbarY = offsets.y;
35815
35904
  this.canScrollVertically = options.canScrollVertically;
@@ -35820,6 +35909,10 @@ class InternalViewport {
35820
35909
  this.adjustViewportOffsetY();
35821
35910
  }
35822
35911
  // PUBLIC
35912
+ /** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
35913
+ * When the viewport grid size is smaller than its client width (resp. height), it will return
35914
+ * the client width (resp. height).
35915
+ */
35823
35916
  getMaxSize() {
35824
35917
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
35825
35918
  first: this.boundaries.left,
@@ -35831,20 +35924,24 @@ class InternalViewport {
35831
35924
  });
35832
35925
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
35833
35926
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
35834
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
35927
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
35835
35928
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
35836
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
35929
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
35837
35930
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
35838
- const width = lastColEnd -
35839
- this.offsetCorrectionX +
35840
- (this.canScrollHorizontally
35841
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
35842
- : 0);
35843
- const height = lastRowEnd -
35844
- this.offsetCorrectionY +
35845
- (this.canScrollVertically
35846
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
35847
- : 0);
35931
+ let width = lastColEnd - this.offsetCorrectionX;
35932
+ if (this.canScrollHorizontally) {
35933
+ width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
35934
+ Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
35935
+ );
35936
+ width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
35937
+ }
35938
+ let height = lastRowEnd - this.offsetCorrectionY;
35939
+ if (this.canScrollVertically) {
35940
+ height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
35941
+ Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
35942
+ );
35943
+ height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
35944
+ }
35848
35945
  return { width, height };
35849
35946
  }
35850
35947
  /**
@@ -35853,7 +35950,7 @@ class InternalViewport {
35853
35950
  * It returns -1 if no column is found.
35854
35951
  */
35855
35952
  getColIndex(x, absolute = false) {
35856
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
35953
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
35857
35954
  return -1;
35858
35955
  }
35859
35956
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -35864,7 +35961,7 @@ class InternalViewport {
35864
35961
  * It returns -1 if no row is found.
35865
35962
  */
35866
35963
  getRowIndex(y, absolute = false) {
35867
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
35964
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
35868
35965
  return -1;
35869
35966
  }
35870
35967
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -35891,7 +35988,7 @@ class InternalViewport {
35891
35988
  adjustPositionX(col) {
35892
35989
  const sheetId = this.sheetId;
35893
35990
  const { start, end } = this.getters.getColDimensions(sheetId, col);
35894
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
35991
+ while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
35895
35992
  this.offsetX + this.offsetCorrectionX < start) {
35896
35993
  this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
35897
35994
  this.offsetScrollbarX = this.offsetX;
@@ -35913,7 +36010,7 @@ class InternalViewport {
35913
36010
  adjustPositionY(row) {
35914
36011
  const sheetId = this.sheetId;
35915
36012
  while (this.getters.getRowDimensions(sheetId, row).end >
35916
- this.offsetY + this.height + this.offsetCorrectionY &&
36013
+ this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
35917
36014
  this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
35918
36015
  this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
35919
36016
  this.offsetScrollbarY = this.offsetY;
@@ -35951,8 +36048,8 @@ class InternalViewport {
35951
36048
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
35952
36049
  this.offsetCorrectionX;
35953
36050
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
35954
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
35955
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
36051
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
36052
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
35956
36053
  return {
35957
36054
  x,
35958
36055
  y,
@@ -36015,12 +36112,12 @@ class InternalViewport {
36015
36112
  adjustViewportOffsetX() {
36016
36113
  if (this.canScrollHorizontally) {
36017
36114
  const { width: viewportWidth } = this.getMaxSize();
36018
- if (this.width + this.offsetScrollbarX > viewportWidth) {
36019
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
36115
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
36116
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
36020
36117
  }
36021
36118
  }
36022
36119
  this.left = this.getColIndex(this.offsetScrollbarX, true);
36023
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
36120
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
36024
36121
  if (this.right === -1) {
36025
36122
  this.right = this.boundaries.right;
36026
36123
  }
@@ -36032,12 +36129,12 @@ class InternalViewport {
36032
36129
  adjustViewportOffsetY() {
36033
36130
  if (this.canScrollVertically) {
36034
36131
  const { height: paneHeight } = this.getMaxSize();
36035
- if (this.height + this.offsetScrollbarY > paneHeight) {
36036
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
36132
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
36133
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
36037
36134
  }
36038
36135
  }
36039
36136
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
36040
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
36137
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
36041
36138
  if (this.bottom === -1) {
36042
36139
  this.bottom = this.boundaries.bottom;
36043
36140
  }
@@ -36048,7 +36145,7 @@ class InternalViewport {
36048
36145
  adjustViewportZoneX() {
36049
36146
  const sheetId = this.sheetId;
36050
36147
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
36051
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
36148
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
36052
36149
  if (this.right === -1) {
36053
36150
  this.right = this.getters.getNumberCols(sheetId) - 1;
36054
36151
  }
@@ -36061,7 +36158,7 @@ class InternalViewport {
36061
36158
  adjustViewportZoneY() {
36062
36159
  const sheetId = this.sheetId;
36063
36160
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
36064
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
36161
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
36065
36162
  if (this.bottom === -1) {
36066
36163
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
36067
36164
  }
@@ -36320,8 +36417,7 @@ class SheetViewPlugin extends UIPlugin {
36320
36417
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
36321
36418
  }
36322
36419
  /**
36323
- * Return the main viewport maximum size. That is the zone dimension
36324
- * with some bottom and right padding.
36420
+ * Return the main viewport maximum size relative to the client size.
36325
36421
  */
36326
36422
  getMainViewportRect() {
36327
36423
  const sheetId = this.getters.getActiveSheetId();
@@ -36337,8 +36433,8 @@ class SheetViewPlugin extends UIPlugin {
36337
36433
  const { width, height } = this.getMainViewportRect();
36338
36434
  const viewport = this.getMainInternalViewport(sheetId);
36339
36435
  return {
36340
- maxOffsetX: Math.max(0, width - viewport.width + 1),
36341
- maxOffsetY: Math.max(0, height - viewport.height + 1),
36436
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
36437
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
36342
36438
  };
36343
36439
  }
36344
36440
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -38355,9 +38451,6 @@ css /* scss */ `
38355
38451
  color: #333;
38356
38452
  }
38357
38453
 
38358
- * {
38359
- font-family: "Roboto", "RobotoDraft", Helvetica, Arial, sans-serif;
38360
- }
38361
38454
  &,
38362
38455
  *,
38363
38456
  *:before,
@@ -39533,6 +39626,7 @@ class RangeAdapter {
39533
39626
  }
39534
39627
  else if (range.zone[start] >= min && range.zone[end] <= max) {
39535
39628
  changeType = "REMOVE";
39629
+ newRange = range.clone({ ...this.getInvalidRange() });
39536
39630
  }
39537
39631
  else if (range.zone[start] <= max && range.zone[end] >= max) {
39538
39632
  const toRemove = max - range.zone[start] + 1;
@@ -39598,8 +39692,10 @@ class RangeAdapter {
39598
39692
  return { changeType: "NONE" };
39599
39693
  }
39600
39694
  const invalidSheetName = this.getters.getSheetName(cmd.sheetId);
39601
- const sheetId = "";
39602
- range = range.clone({ sheetId, invalidSheetName });
39695
+ range = range.clone({
39696
+ ...this.getInvalidRange(),
39697
+ invalidSheetName,
39698
+ });
39603
39699
  return { changeType: "REMOVE", range };
39604
39700
  }, cmd.sheetId);
39605
39701
  break;
@@ -39863,6 +39959,15 @@ class RangeAdapter {
39863
39959
  }
39864
39960
  return str;
39865
39961
  }
39962
+ getInvalidRange() {
39963
+ return {
39964
+ parts: [],
39965
+ prefixSheet: false,
39966
+ zone: { left: -1, top: -1, right: -1, bottom: -1 },
39967
+ sheetId: "",
39968
+ invalidXc: INCORRECT_RANGE_STRING,
39969
+ };
39970
+ }
39866
39971
  }
39867
39972
  RangeAdapter.getters = [
39868
39973
  "getRangeString",
@@ -42439,6 +42544,6 @@ function addFunction(functionName, functionDescription) {
42439
42544
  export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, cellTypes, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, load, parse, readonlyAllowedCommands, registries, setTranslationMethod, tokenize };
42440
42545
 
42441
42546
 
42442
- __info__.version = '16.0.4';
42443
- __info__.date = '2023-03-16T12:11:01.007Z';
42444
- __info__.hash = 'ebbb1f0';
42547
+ __info__.version = '16.0.6';
42548
+ __info__.date = '2023-04-13T08:30:26.954Z';
42549
+ __info__.hash = '8d60b5c';