@odoo/o-spreadsheet 16.1.5 → 16.1.7

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;
@@ -231,7 +231,7 @@ const DEFAULT_FONT = "'Roboto', arial";
231
231
  const DEFAULT_BORDER_DESC = ["thin", "#000"];
232
232
  const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
233
233
  // DateTimeRegex
234
- const DATETIME_FORMAT = /[ymd:]/;
234
+ const DATETIME_FORMAT = /[ymdhs:]/;
235
235
  // Ranges
236
236
  const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
237
237
  // Max Number of history steps kept in memory
@@ -268,11 +268,13 @@ var ComponentsImportance;
268
268
  ComponentsImportance[ComponentsImportance["Highlight"] = 5] = "Highlight";
269
269
  ComponentsImportance[ComponentsImportance["Figure"] = 10] = "Figure";
270
270
  ComponentsImportance[ComponentsImportance["ScrollBar"] = 15] = "ScrollBar";
271
- ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
272
- ComponentsImportance[ComponentsImportance["Composer"] = 20] = "Composer";
271
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
272
+ ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
273
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
273
274
  ComponentsImportance[ComponentsImportance["ColorPicker"] = 25] = "ColorPicker";
274
275
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
275
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
276
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
277
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
276
278
  ComponentsImportance[ComponentsImportance["ChartAnchor"] = 1000] = "ChartAnchor";
277
279
  })(ComponentsImportance || (ComponentsImportance = {}));
278
280
  const DEFAULT_SHEETVIEW_SIZE = 1000;
@@ -1035,6 +1037,8 @@ function transpose2dArray(matrix) {
1035
1037
  return matrix[0].map((_, i) => matrix.map((row) => row[i]));
1036
1038
  }
1037
1039
 
1040
+ const RBA_REGEX = /rgba?\(|\s+|\)/gi;
1041
+ const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
1038
1042
  const colors$1 = [
1039
1043
  "#eb6d00",
1040
1044
  "#0074d9",
@@ -1060,7 +1064,10 @@ function colorNumberString(color) {
1060
1064
  }
1061
1065
  /**
1062
1066
  * Converts any CSS color value to a standardized hex6 value.
1063
- * Accepts: hex3, hex6, hex8 and rgb (rgba is not supported)
1067
+ * Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
1068
+ *
1069
+ * [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
1070
+ * with r,g,b ∈ [0, 255] and a ∈ [0, 1]
1064
1071
  *
1065
1072
  * toHex("#ABC")
1066
1073
  * >> "#AABBCC"
@@ -1071,27 +1078,31 @@ function colorNumberString(color) {
1071
1078
  * toHex("rgb(30, 80, 16)")
1072
1079
  * >> "#1E5010"
1073
1080
  *
1081
+ * * toHex("rgb(30, 80, 16, 0.5)")
1082
+ * >> "#1E501080"
1083
+ *
1074
1084
  */
1075
1085
  function toHex(color) {
1076
- if (color.includes("rgba")) {
1077
- throw new Error(`rgba() conversion currently not supported: ${color}`);
1086
+ let hexColor = color;
1087
+ if (color.startsWith("rgb")) {
1088
+ hexColor = rgbaStringToHex(color);
1078
1089
  }
1079
- if (color.includes("rgb")) {
1080
- return rgbToHex6(color);
1081
- }
1082
- color = color.replace("#", "").toUpperCase();
1083
- if (color.length === 3 || color.length === 4) {
1084
- color = color.split("").reduce((acc, h) => acc + h + h, "");
1090
+ else {
1091
+ hexColor = color.replace("#", "").toUpperCase();
1092
+ if (hexColor.length === 3 || hexColor.length === 4) {
1093
+ hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
1094
+ }
1095
+ hexColor = `#${hexColor}`;
1085
1096
  }
1086
- if (color.replace(/[a-f0-9]/gi, "") !== "") {
1087
- throw new Error("invalid color");
1097
+ if (!hexColor.match(HEX_MATCH)) {
1098
+ throw new Error(`invalid color input: ${color}`);
1088
1099
  }
1089
- return "#" + color;
1100
+ return hexColor;
1090
1101
  }
1091
1102
  function isColorValid(color) {
1092
1103
  try {
1093
- const { r, g, b, a } = colorToRGBA(color);
1094
- return (isColorValueValid(r) && isColorValueValid(g) && isColorValueValid(b) && isColorValueValid(a));
1104
+ toHex(color);
1105
+ return true;
1095
1106
  }
1096
1107
  catch (error) {
1097
1108
  return false;
@@ -1124,15 +1135,29 @@ function relativeLuminance(color) {
1124
1135
  /**
1125
1136
  * Convert a CSS rgb color string to a standardized hex6 color value.
1126
1137
  *
1127
- * rgbToHex6("rgb(30, 80, 16)")
1138
+ * rgbaStringToHex("rgb(30, 80, 16)")
1128
1139
  * >> "#1E5010"
1140
+ *
1141
+ * rgbaStringToHex("rgba(30, 80, 16, 0.5)")
1142
+ * >> "#1E501080"
1143
+ *
1144
+ * DOES NOT SUPPORT NON INTEGER RGB VALUES
1129
1145
  */
1130
- function rgbToHex6(color) {
1131
- return ("#" +
1132
- concat(color
1133
- .slice(4, -1)
1134
- .split(",")
1135
- .map((valueString) => parseInt(valueString, 10).toString(16).padStart(2, "0"))).toUpperCase());
1146
+ function rgbaStringToHex(color) {
1147
+ const stringVals = color.replace(RBA_REGEX, "").split(",");
1148
+ let alphaHex = 255;
1149
+ if (stringVals.length !== 3 && stringVals.length !== 4) {
1150
+ throw new Error("invalid color");
1151
+ }
1152
+ else if (stringVals.length === 4) {
1153
+ const alpha = parseFloat(stringVals.pop() || "1");
1154
+ alphaHex = Math.round((alpha || 1) * 255);
1155
+ }
1156
+ const vals = stringVals.map((val) => parseInt(val, 10));
1157
+ if (alphaHex !== 255) {
1158
+ vals.push(alphaHex);
1159
+ }
1160
+ return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
1136
1161
  }
1137
1162
  /**
1138
1163
  * RGBA to HEX representation (#RRGGBBAA).
@@ -1154,7 +1179,7 @@ function rgbaToHex(rgba) {
1154
1179
  a = "0" + a;
1155
1180
  if (a === "ff")
1156
1181
  a = "";
1157
- return "#" + r + g + b + a;
1182
+ return ("#" + r + g + b + a).toUpperCase();
1158
1183
  }
1159
1184
  /**
1160
1185
  * Color string to RGBA representation
@@ -1275,6 +1300,9 @@ function rgbaToHSLA(rgba) {
1275
1300
  s = +(s * 100).toFixed(1);
1276
1301
  l = +(l * 100).toFixed(1);
1277
1302
  return { a: rgba.a, h, s, l };
1303
+ }
1304
+ function isSameColor(color1, color2) {
1305
+ return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
1278
1306
  }
1279
1307
 
1280
1308
  /** Reference of a cell (eg. A1, $B$5) */
@@ -1426,7 +1454,7 @@ function scrollDelay(value) {
1426
1454
  * formula, commas are used to separate arguments
1427
1455
  * - it does not support % symbol, in formulas % is an operator
1428
1456
  */
1429
- const formulaNumberRegexp = /^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+/;
1457
+ const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
1430
1458
  const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
1431
1459
  const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
1432
1460
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -3021,6 +3049,7 @@ const CHART_PADDING_RATIO = 0.02;
3021
3049
  const LINE_HEIGHT = 1.2;
3022
3050
  css /* scss */ `
3023
3051
  div.o-scorecard {
3052
+ font-family: ${DEFAULT_FONT};
3024
3053
  user-select: none;
3025
3054
  background-color: white;
3026
3055
  display: flex;
@@ -5645,6 +5674,11 @@ class Popover extends Component {
5645
5674
  this.currentPosition = newPosition;
5646
5675
  });
5647
5676
  }
5677
+ get popoverStyle() {
5678
+ return cssPropertiesToCss({
5679
+ "z-index": `${this.props.zIndex}`,
5680
+ });
5681
+ }
5648
5682
  }
5649
5683
  Popover.template = "o-spreadsheet-Popover";
5650
5684
  Popover.defaultProps = {
@@ -5653,6 +5687,7 @@ Popover.defaultProps = {
5653
5687
  onMouseWheel: () => { },
5654
5688
  onPopoverMoved: () => { },
5655
5689
  onPopoverHidden: () => { },
5690
+ zIndex: ComponentsImportance.Popover,
5656
5691
  };
5657
5692
  Popover.props = {
5658
5693
  anchorRect: Object,
@@ -5664,6 +5699,7 @@ Popover.props = {
5664
5699
  onMouseWheel: { type: Function, optional: true },
5665
5700
  onPopoverHidden: { type: Function, optional: true },
5666
5701
  onPopoverMoved: { type: Function, optional: true },
5702
+ zIndex: { type: Number, optional: true },
5667
5703
  slots: Object,
5668
5704
  };
5669
5705
  class PopoverPositionContext {
@@ -16521,6 +16557,7 @@ class EditionPlugin extends UIPlugin {
16521
16557
  this.setContent(this.initialContent || "");
16522
16558
  }
16523
16559
  setContent(text, selection, raise) {
16560
+ text = text.replace(/[\r\n]/g, "");
16524
16561
  const isNewCurrentContent = this.currentContent !== text;
16525
16562
  this.currentContent = text;
16526
16563
  if (selection) {
@@ -16805,6 +16842,8 @@ class ContentEditableHelper {
16805
16842
  start = 0;
16806
16843
  if (end > this.el.textContent.length)
16807
16844
  end = this.el.textContent.length;
16845
+ if (start > this.el.textContent.length)
16846
+ start = this.el.textContent.length;
16808
16847
  }
16809
16848
  let startNode = this.findChildAtCharacterIndex(start);
16810
16849
  let endNode = this.findChildAtCharacterIndex(end);
@@ -17031,10 +17070,10 @@ css /* scss */ `
17031
17070
  padding: 0;
17032
17071
  margin: 0;
17033
17072
  border: 0;
17034
- z-index: ${ComponentsImportance.Composer};
17035
17073
  flex-grow: 1;
17036
17074
  max-height: inherit;
17037
17075
  .o-composer {
17076
+ font-family: ${DEFAULT_FONT};
17038
17077
  caret-color: black;
17039
17078
  padding-left: 3px;
17040
17079
  padding-right: 3px;
@@ -17069,6 +17108,10 @@ css /* scss */ `
17069
17108
  .o-topbar-toolbar .o-composer-container:focus-within {
17070
17109
  border: 1px solid ${SELECTION_BORDER_COLOR};
17071
17110
  }
17111
+
17112
+ .o-topbar-toolbar .o-composer-container {
17113
+ z-index: ${ComponentsImportance.TopBarComposer};
17114
+ }
17072
17115
  `;
17073
17116
  class Composer extends Component {
17074
17117
  constructor() {
@@ -17517,7 +17560,7 @@ const SCROLLBAR_HIGHT = 15;
17517
17560
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
17518
17561
  css /* scss */ `
17519
17562
  div.o-grid-composer {
17520
- z-index: ${ComponentsImportance.Composer};
17563
+ z-index: ${ComponentsImportance.GridComposer};
17521
17564
  box-sizing: border-box;
17522
17565
  position: absolute;
17523
17566
  border: ${COMPOSER_BORDER_WIDTH}px solid ${SELECTION_BORDER_COLOR};
@@ -20053,6 +20096,9 @@ class ColorPicker extends Component {
20053
20096
  const { display, background, left, top } = this.state.style;
20054
20097
  return `display:${display};${display === "block" ? `background-color:${background};left:${left};top:${top};` : ""}`;
20055
20098
  }
20099
+ isSameColor(color1, color2) {
20100
+ return isSameColor(color1, color2);
20101
+ }
20056
20102
  }
20057
20103
  ColorPicker.template = "o-spreadsheet-ColorPicker";
20058
20104
  ColorPicker.defaultProps = {
@@ -20197,6 +20243,12 @@ class GaugeChartDesignPanel extends Component {
20197
20243
  const cancelledReasons = [...(((_a = this.state.sectionRuleDispatchResult) === null || _a === void 0 ? void 0 : _a.reasons) || [])];
20198
20244
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
20199
20245
  }
20246
+ onClick(ev) {
20247
+ this.state.openedMenu = undefined;
20248
+ }
20249
+ setup() {
20250
+ useExternalListener(window, "click", this.onClick);
20251
+ }
20200
20252
  updateBackgroundColor(color) {
20201
20253
  this.state.openedMenu = undefined;
20202
20254
  this.props.updateChart({
@@ -20380,6 +20432,12 @@ class ScorecardChartDesignPanel extends Component {
20380
20432
  openedColorPicker: undefined,
20381
20433
  });
20382
20434
  }
20435
+ onClick(ev) {
20436
+ this.state.openedColorPicker = undefined;
20437
+ }
20438
+ setup() {
20439
+ useExternalListener(window, "click", this.onClick);
20440
+ }
20383
20441
  updateTitle(ev) {
20384
20442
  this.props.updateChart({
20385
20443
  title: ev.target.value,
@@ -22283,6 +22341,9 @@ class GridOverlay extends Component {
22283
22341
  onMounted(() => {
22284
22342
  resizeObserver.observe(this.gridOverlayEl);
22285
22343
  });
22344
+ onWillUnmount(() => {
22345
+ resizeObserver.disconnect();
22346
+ });
22286
22347
  useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
22287
22348
  const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
22288
22349
  return scrollY > 0;
@@ -22339,6 +22400,10 @@ GridOverlay.props = {
22339
22400
  };
22340
22401
 
22341
22402
  class GridPopover extends Component {
22403
+ constructor() {
22404
+ super(...arguments);
22405
+ this.zIndex = ComponentsImportance.GridPopover;
22406
+ }
22342
22407
  get cellPopover() {
22343
22408
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
22344
22409
  if (!popover.isOpen) {
@@ -23703,6 +23768,10 @@ class Grid extends Component {
23703
23768
  }
23704
23769
  }
23705
23770
  onInput(ev) {
23771
+ // the user meant to paste in the sheet, not open the composer with the pasted content
23772
+ if (!ev.isComposing && ev.inputType === "insertFromPaste") {
23773
+ return;
23774
+ }
23706
23775
  if (ev.data) {
23707
23776
  // if the user types a character on the grid, it means he wants to start composing the selected cell with that
23708
23777
  // character
@@ -24552,6 +24621,70 @@ function fixXlsxUnicode(str) {
24552
24621
  });
24553
24622
  }
24554
24623
 
24624
+ 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;
24625
+ /**
24626
+ * Convert excel format to o_spreadsheet format
24627
+ *
24628
+ * Excel format are defined in openXML §18.8.31
24629
+ */
24630
+ function convertXlsxFormat(numFmtId, formats, warningManager) {
24631
+ var _a, _b, _c;
24632
+ if (numFmtId === 0) {
24633
+ return undefined;
24634
+ }
24635
+ // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
24636
+ let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
24637
+ if (format) {
24638
+ try {
24639
+ let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
24640
+ convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
24641
+ convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
24642
+ // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
24643
+ const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
24644
+ const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
24645
+ if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
24646
+ throw new Error("Multiple escaped blocks in format");
24647
+ }
24648
+ convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
24649
+ convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
24650
+ convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
24651
+ convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
24652
+ convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
24653
+ if (isXlsxDateFormat(convertedFormat)) {
24654
+ convertedFormat = convertDateFormat$1(convertedFormat);
24655
+ }
24656
+ if (isFormatSupported(convertedFormat)) {
24657
+ return convertedFormat;
24658
+ }
24659
+ }
24660
+ catch (e) { }
24661
+ }
24662
+ warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
24663
+ return undefined;
24664
+ }
24665
+ function isFormatSupported(format) {
24666
+ try {
24667
+ formatValue(0, format);
24668
+ return true;
24669
+ }
24670
+ catch (e) {
24671
+ return false;
24672
+ }
24673
+ }
24674
+ function isXlsxDateFormat(format) {
24675
+ return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
24676
+ }
24677
+ function convertDateFormat$1(format) {
24678
+ // Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
24679
+ // but can still occur and are supported by Excel/Google sheets
24680
+ format = format.toLowerCase();
24681
+ format = format.replace(/mmmmm/g, "mmm");
24682
+ format = format.replace(/am\/pm|a\/m/g, "a");
24683
+ format = format.replace(/hhhh/g, "hh");
24684
+ format = format.replace(/\bh\b/g, "hh");
24685
+ return format;
24686
+ }
24687
+
24555
24688
  function convertBorders(data, warningManager) {
24556
24689
  const borderArray = data.borders.map((border) => {
24557
24690
  addBorderWarnings(border, warningManager);
@@ -24616,41 +24749,6 @@ function convertFormats(data, warningManager) {
24616
24749
  }
24617
24750
  return arrayToObject(formats, 1);
24618
24751
  }
24619
- /**
24620
- * Convert excel format to o_spreadsheet format
24621
- *
24622
- * Excel format are defined in openXML §18.8.31
24623
- */
24624
- function convertXlsxFormat(numFmtId, formats, warningManager) {
24625
- var _a, _b, _c;
24626
- if (numFmtId === 0) {
24627
- return undefined;
24628
- }
24629
- // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
24630
- let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
24631
- if (format) {
24632
- try {
24633
- let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
24634
- convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
24635
- convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
24636
- // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
24637
- const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
24638
- const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
24639
- if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
24640
- throw new Error("Multiple escaped blocks in format");
24641
- }
24642
- convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
24643
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
24644
- convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
24645
- convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
24646
- formatValue(0, convertedFormat);
24647
- return convertedFormat;
24648
- }
24649
- catch (e) { }
24650
- }
24651
- warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
24652
- return undefined;
24653
- }
24654
24752
  /**
24655
24753
  * We currently only support only a set of font sizes, we cannot define new font sizes.
24656
24754
  * This function adapts an arbitrary font size to the closest supported font size.
@@ -30515,6 +30613,7 @@ class RangeAdapter {
30515
30613
  }
30516
30614
  else if (range.zone[start] >= min && range.zone[end] <= max) {
30517
30615
  changeType = "REMOVE";
30616
+ newRange = range.clone({ ...this.getInvalidRange() });
30518
30617
  }
30519
30618
  else if (range.zone[start] <= max && range.zone[end] >= max) {
30520
30619
  const toRemove = max - range.zone[start] + 1;
@@ -30580,8 +30679,10 @@ class RangeAdapter {
30580
30679
  return { changeType: "NONE" };
30581
30680
  }
30582
30681
  const invalidSheetName = this.getters.getSheetName(cmd.sheetId);
30583
- const sheetId = "";
30584
- range = range.clone({ sheetId, invalidSheetName });
30682
+ range = range.clone({
30683
+ ...this.getInvalidRange(),
30684
+ invalidSheetName,
30685
+ });
30585
30686
  return { changeType: "REMOVE", range };
30586
30687
  }, cmd.sheetId);
30587
30688
  break;
@@ -30841,6 +30942,15 @@ class RangeAdapter {
30841
30942
  }
30842
30943
  return str;
30843
30944
  }
30945
+ getInvalidRange() {
30946
+ return {
30947
+ parts: [],
30948
+ prefixSheet: false,
30949
+ zone: { left: -1, top: -1, right: -1, bottom: -1 },
30950
+ sheetId: "",
30951
+ invalidXc: INCORRECT_RANGE_STRING,
30952
+ };
30953
+ }
30844
30954
  }
30845
30955
  RangeAdapter.getters = [
30846
30956
  "getRangeString",
@@ -31805,9 +31915,7 @@ class CustomColorsPlugin extends UIPlugin {
31805
31915
  // remove duplicates first to check validity on a reduced
31806
31916
  // set of colors, then normalize to HEX and remove duplicates
31807
31917
  // again
31808
- [...new Set([...usedColors, ...this.customColors])]
31809
- .filter(isColorValid)
31810
- .map((c) => toHex(c).toLowerCase())),
31918
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
31811
31919
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
31812
31920
  }
31813
31921
  getColorsFromCells(cells) {
@@ -31868,7 +31976,7 @@ class CustomColorsPlugin extends UIPlugin {
31868
31976
  return [...chartsColors];
31869
31977
  }
31870
31978
  tryToAddColor(color) {
31871
- const formattedColor = toHex(color).toLowerCase();
31979
+ const formattedColor = toHex(color);
31872
31980
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
31873
31981
  this.customColors.add(formattedColor);
31874
31982
  }
@@ -32873,8 +32981,8 @@ class InternalViewport {
32873
32981
  this.getters = getters;
32874
32982
  this.sheetId = sheetId;
32875
32983
  this.boundaries = boundaries;
32876
- this.width = sizeInGrid.width;
32877
- this.height = sizeInGrid.height;
32984
+ this.viewportWidth = sizeInGrid.width;
32985
+ this.viewportHeight = sizeInGrid.height;
32878
32986
  this.offsetScrollbarX = offsets.x;
32879
32987
  this.offsetScrollbarY = offsets.y;
32880
32988
  this.canScrollVertically = options.canScrollVertically;
@@ -32885,6 +32993,10 @@ class InternalViewport {
32885
32993
  this.adjustViewportOffsetY();
32886
32994
  }
32887
32995
  // PUBLIC
32996
+ /** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
32997
+ * When the viewport grid size is smaller than its client width (resp. height), it will return
32998
+ * the client width (resp. height).
32999
+ */
32888
33000
  getMaxSize() {
32889
33001
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
32890
33002
  first: this.boundaries.left,
@@ -32896,20 +33008,24 @@ class InternalViewport {
32896
33008
  });
32897
33009
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
32898
33010
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
32899
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
33011
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
32900
33012
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
32901
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
33013
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
32902
33014
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
32903
- const width = lastColEnd -
32904
- this.offsetCorrectionX +
32905
- (this.canScrollHorizontally
32906
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
32907
- : 0);
32908
- const height = lastRowEnd -
32909
- this.offsetCorrectionY +
32910
- (this.canScrollVertically
32911
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
32912
- : 0);
33015
+ let width = lastColEnd - this.offsetCorrectionX;
33016
+ if (this.canScrollHorizontally) {
33017
+ width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
33018
+ Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
33019
+ );
33020
+ width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
33021
+ }
33022
+ let height = lastRowEnd - this.offsetCorrectionY;
33023
+ if (this.canScrollVertically) {
33024
+ height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
33025
+ Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
33026
+ );
33027
+ height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
33028
+ }
32913
33029
  return { width, height };
32914
33030
  }
32915
33031
  /**
@@ -32918,7 +33034,7 @@ class InternalViewport {
32918
33034
  * It returns -1 if no column is found.
32919
33035
  */
32920
33036
  getColIndex(x, absolute = false) {
32921
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
33037
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
32922
33038
  return -1;
32923
33039
  }
32924
33040
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -32929,7 +33045,7 @@ class InternalViewport {
32929
33045
  * It returns -1 if no row is found.
32930
33046
  */
32931
33047
  getRowIndex(y, absolute = false) {
32932
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
33048
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
32933
33049
  return -1;
32934
33050
  }
32935
33051
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -32956,7 +33072,7 @@ class InternalViewport {
32956
33072
  adjustPositionX(col) {
32957
33073
  const sheetId = this.sheetId;
32958
33074
  const { start, end } = this.getters.getColDimensions(sheetId, col);
32959
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
33075
+ while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
32960
33076
  this.offsetX + this.offsetCorrectionX < start) {
32961
33077
  this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
32962
33078
  this.offsetScrollbarX = this.offsetX;
@@ -32978,7 +33094,7 @@ class InternalViewport {
32978
33094
  adjustPositionY(row) {
32979
33095
  const sheetId = this.sheetId;
32980
33096
  while (this.getters.getRowDimensions(sheetId, row).end >
32981
- this.offsetY + this.height + this.offsetCorrectionY &&
33097
+ this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
32982
33098
  this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
32983
33099
  this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
32984
33100
  this.offsetScrollbarY = this.offsetY;
@@ -33016,8 +33132,8 @@ class InternalViewport {
33016
33132
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
33017
33133
  this.offsetCorrectionX;
33018
33134
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
33019
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
33020
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
33135
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
33136
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
33021
33137
  return {
33022
33138
  x,
33023
33139
  y,
@@ -33080,12 +33196,12 @@ class InternalViewport {
33080
33196
  adjustViewportOffsetX() {
33081
33197
  if (this.canScrollHorizontally) {
33082
33198
  const { width: viewportWidth } = this.getMaxSize();
33083
- if (this.width + this.offsetScrollbarX > viewportWidth) {
33084
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
33199
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
33200
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
33085
33201
  }
33086
33202
  }
33087
33203
  this.left = this.getColIndex(this.offsetScrollbarX, true);
33088
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
33204
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
33089
33205
  if (this.right === -1) {
33090
33206
  this.right = this.boundaries.right;
33091
33207
  }
@@ -33097,12 +33213,12 @@ class InternalViewport {
33097
33213
  adjustViewportOffsetY() {
33098
33214
  if (this.canScrollVertically) {
33099
33215
  const { height: paneHeight } = this.getMaxSize();
33100
- if (this.height + this.offsetScrollbarY > paneHeight) {
33101
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
33216
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
33217
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
33102
33218
  }
33103
33219
  }
33104
33220
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
33105
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
33221
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
33106
33222
  if (this.bottom === -1) {
33107
33223
  this.bottom = this.boundaries.bottom;
33108
33224
  }
@@ -33113,7 +33229,7 @@ class InternalViewport {
33113
33229
  adjustViewportZoneX() {
33114
33230
  const sheetId = this.sheetId;
33115
33231
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
33116
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
33232
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
33117
33233
  if (this.right === -1) {
33118
33234
  this.right = this.getters.getNumberCols(sheetId) - 1;
33119
33235
  }
@@ -33126,7 +33242,7 @@ class InternalViewport {
33126
33242
  adjustViewportZoneY() {
33127
33243
  const sheetId = this.sheetId;
33128
33244
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
33129
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
33245
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
33130
33246
  if (this.bottom === -1) {
33131
33247
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
33132
33248
  }
@@ -33388,8 +33504,7 @@ class SheetViewPlugin extends UIPlugin {
33388
33504
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
33389
33505
  }
33390
33506
  /**
33391
- * Return the main viewport maximum size. That is the zone dimension
33392
- * with some bottom and right padding.
33507
+ * Return the main viewport maximum size relative to the client size.
33393
33508
  */
33394
33509
  getMainViewportRect() {
33395
33510
  const sheetId = this.getters.getActiveSheetId();
@@ -33405,8 +33520,8 @@ class SheetViewPlugin extends UIPlugin {
33405
33520
  const { width, height } = this.getMainViewportRect();
33406
33521
  const viewport = this.getMainInternalViewport(sheetId);
33407
33522
  return {
33408
- maxOffsetX: Math.max(0, width - viewport.width + 1),
33409
- maxOffsetY: Math.max(0, height - viewport.height + 1),
33523
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
33524
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
33410
33525
  };
33411
33526
  }
33412
33527
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -39890,6 +40005,7 @@ class TopBar extends Component {
39890
40005
  this.state.menuState.parentMenu = menu;
39891
40006
  this.isSelectingMenu = true;
39892
40007
  this.openedEl = ev.target;
40008
+ this.env.model.dispatch("STOP_EDITION");
39893
40009
  }
39894
40010
  closeMenus() {
39895
40011
  this.state.activeTool = "";
@@ -40109,9 +40225,6 @@ css /* scss */ `
40109
40225
  color: #333;
40110
40226
  }
40111
40227
 
40112
- * {
40113
- font-family: "Roboto", "RobotoDraft", Helvetica, Arial, sans-serif;
40114
- }
40115
40228
  &,
40116
40229
  *,
40117
40230
  *:before,
@@ -43879,6 +43992,6 @@ function addFunction(functionName, functionDescription) {
43879
43992
  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 };
43880
43993
 
43881
43994
 
43882
- __info__.version = '16.1.5';
43883
- __info__.date = '2023-03-16T12:12:08.747Z';
43884
- __info__.hash = '12f7a8e';
43995
+ __info__.version = '16.1.7';
43996
+ __info__.date = '2023-04-13T08:29:52.140Z';
43997
+ __info__.hash = '3141a6d';