@odoo/o-spreadsheet 16.3.0-alpha.2 → 16.3.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -113,88 +113,89 @@ const FILTERS_COLOR = "#188038";
113
113
  const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
114
114
  const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
115
115
  const SEPARATOR_COLOR = "#E0E2E4";
116
- // Color picker
116
+ const ICONS_COLOR = "#4A4F59";
117
+ // Color picker defaults as upper case HEX to match `toHex`helper
117
118
  const COLOR_PICKER_DEFAULTS = [
118
119
  "#000000",
119
120
  "#434343",
120
121
  "#666666",
121
122
  "#999999",
122
- "#b7b7b7",
123
- "#cccccc",
124
- "#d9d9d9",
125
- "#efefef",
126
- "#f3f3f3",
127
- "#ffffff",
123
+ "#B7B7B7",
124
+ "#CCCCCC",
125
+ "#D9D9D9",
126
+ "#EFEFEF",
127
+ "#F3F3F3",
128
+ "#FFFFFF",
128
129
  "#980000",
129
- "#ff0000",
130
- "#ff9900",
131
- "#ffff00",
132
- "#00ff00",
133
- "#00ffff",
134
- "#4a86e8",
135
- "#0000ff",
136
- "#9900ff",
137
- "#ff00ff",
138
- "#e6b8af",
139
- "#f4cccc",
140
- "#fce5cd",
141
- "#fff2cc",
142
- "#d9ead3",
143
- "#d0e0e3",
144
- "#c9daf8",
145
- "#cfe2f3",
146
- "#d9d2e9",
147
- "#ead1dc",
148
- "#dd7e6b",
149
- "#ea9999",
150
- "#f9cb9c",
151
- "#ffe599",
152
- "#b6d7a8",
153
- "#a2c4c9",
154
- "#a4c2f4",
155
- "#9fc5e8",
156
- "#b4a7d6",
157
- "#d5a6bd",
158
- "#cc4125",
159
- "#e06666",
160
- "#f6b26b",
161
- "#ffd966",
162
- "#93c47d",
163
- "#76a5af",
164
- "#6d9eeb",
165
- "#6fa8dc",
166
- "#8e7cc3",
167
- "#c27ba0",
168
- "#a61c00",
169
- "#cc0000",
170
- "#e69138",
171
- "#f1c232",
172
- "#6aa84f",
173
- "#45818e",
174
- "#3c78d8",
175
- "#3d85c6",
176
- "#674ea7",
177
- "#a64d79",
178
- "#85200c",
130
+ "#FF0000",
131
+ "#FF9900",
132
+ "#FFFF00",
133
+ "#00FF00",
134
+ "#00FFFF",
135
+ "#4A86E8",
136
+ "#0000FF",
137
+ "#9900FF",
138
+ "#FF00FF",
139
+ "#E6B8AF",
140
+ "#F4CCCC",
141
+ "#FCE5CD",
142
+ "#FFF2CC",
143
+ "#D9EAD3",
144
+ "#D0E0E3",
145
+ "#C9DAF8",
146
+ "#CFE2F3",
147
+ "#D9D2E9",
148
+ "#EAD1DC",
149
+ "#DD7E6B",
150
+ "#EA9999",
151
+ "#F9CB9C",
152
+ "#FFE599",
153
+ "#B6D7A8",
154
+ "#A2C4C9",
155
+ "#A4C2F4",
156
+ "#9FC5E8",
157
+ "#B4A7D6",
158
+ "#D5A6BD",
159
+ "#CC4125",
160
+ "#E06666",
161
+ "#F6B26B",
162
+ "#FFD966",
163
+ "#93C47D",
164
+ "#76A5AF",
165
+ "#6D9EEB",
166
+ "#6FA8DC",
167
+ "#8E7CC3",
168
+ "#C27BA0",
169
+ "#A61C00",
170
+ "#CC0000",
171
+ "#E69138",
172
+ "#F1C232",
173
+ "#6AA84F",
174
+ "#45818E",
175
+ "#3C78D8",
176
+ "#3D85C6",
177
+ "#674EA7",
178
+ "#A64D79",
179
+ "#85200C",
179
180
  "#990000",
180
- "#b45f06",
181
- "#bf9000",
182
- "#38761d",
183
- "#134f5c",
184
- "#1155cc",
185
- "#0b5394",
186
- "#351c75",
187
- "#741b47",
188
- "#5b0f00",
181
+ "#B45F06",
182
+ "#BF9000",
183
+ "#38761D",
184
+ "#134F5C",
185
+ "#1155CC",
186
+ "#0B5394",
187
+ "#351C75",
188
+ "#741B47",
189
+ "#5B0F00",
189
190
  "#660000",
190
- "#783f04",
191
- "#7f6000",
192
- "#274e13",
193
- "#0c343d",
194
- "#1c4587",
191
+ "#783F04",
192
+ "#7F6000",
193
+ "#274E13",
194
+ "#0C343D",
195
+ "#1C4587",
195
196
  "#073763",
196
- "#20124d",
197
- "#4c1130",
197
+ "#20124D",
198
+ "#4C1130",
198
199
  ];
199
200
  // Dimensions
200
201
  const MIN_ROW_HEIGHT = 10;
@@ -219,21 +220,23 @@ const FILTER_ICON_MARGIN = 2;
219
220
  const FILTER_ICON_EDGE_LENGTH = 17;
220
221
  // Menus
221
222
  const MENU_WIDTH = 250;
222
- const MENU_VERTICAL_PADDING = 8;
223
- const MENU_ITEM_HEIGHT = 28;
223
+ const MENU_VERTICAL_PADDING = 6;
224
+ const MENU_ITEM_HEIGHT = 26;
225
+ const MENU_ITEM_PADDING_HORIZONTAL = 13;
226
+ const MENU_ITEM_PADDING_VERTICAL = 4;
224
227
  const MENU_SEPARATOR_BORDER_WIDTH = 1;
225
228
  const MENU_SEPARATOR_PADDING = 5;
226
- const MENU_SEPARATOR_HEIGHT = MENU_SEPARATOR_BORDER_WIDTH + 2 * MENU_SEPARATOR_PADDING;
227
229
  // Fonts
228
230
  const DEFAULT_FONT_WEIGHT = "400";
229
231
  const DEFAULT_FONT_SIZE = 10;
230
232
  const HEADER_FONT_SIZE = 11;
231
233
  const DEFAULT_FONT = "'Roboto', arial";
234
+ const DEFAULT_VERTICAL_ALIGN = "middle";
232
235
  // Borders
233
236
  const DEFAULT_BORDER_DESC = ["thin", "#000"];
234
237
  const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
235
238
  // DateTimeRegex
236
- const DATETIME_FORMAT = /[ymd:]/;
239
+ const DATETIME_FORMAT = /[ymdhs:]/;
237
240
  // Ranges
238
241
  const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
239
242
  // Max Number of history steps kept in memory
@@ -271,15 +274,22 @@ var ComponentsImportance;
271
274
  ComponentsImportance[ComponentsImportance["Highlight"] = 5] = "Highlight";
272
275
  ComponentsImportance[ComponentsImportance["Figure"] = 10] = "Figure";
273
276
  ComponentsImportance[ComponentsImportance["ScrollBar"] = 15] = "ScrollBar";
274
- ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
277
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
275
278
  ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
276
- ComponentsImportance[ComponentsImportance["TopBarComposer"] = 21] = "TopBarComposer";
279
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
277
280
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
278
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
281
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
282
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
279
283
  ComponentsImportance[ComponentsImportance["FigureAnchor"] = 1000] = "FigureAnchor";
280
284
  ComponentsImportance[ComponentsImportance["FigureSnapLine"] = 1001] = "FigureSnapLine";
281
285
  })(ComponentsImportance || (ComponentsImportance = {}));
282
- const DEFAULT_SHEETVIEW_SIZE = 1000;
286
+ let DEFAULT_SHEETVIEW_SIZE = 0;
287
+ function getDefaultSheetViewSize() {
288
+ return DEFAULT_SHEETVIEW_SIZE;
289
+ }
290
+ function setDefaultSheetViewSize(size) {
291
+ DEFAULT_SHEETVIEW_SIZE = size;
292
+ }
283
293
  const MAXIMAL_FREEZABLE_RATIO = 0.85;
284
294
  const NEWLINE = "\n";
285
295
  const FONT_SIZES = [6, 7, 8, 9, 10, 11, 12, 14, 18, 24, 36];
@@ -714,7 +724,7 @@ function getUnquotedSheetName(sheetName) {
714
724
  * '\w' captures [0-9][a-z][A-Z] and _.
715
725
  * @param sheetName Name of the sheet
716
726
  */
717
- function getComposerSheetName(sheetName) {
727
+ function getCanonicalSheetName(sheetName) {
718
728
  var _a;
719
729
  if (((_a = sheetName.match(/\w/g)) === null || _a === void 0 ? void 0 : _a.length) !== sheetName.length) {
720
730
  sheetName = `'${sheetName}'`;
@@ -735,8 +745,9 @@ function getDefaultCellHeight(cell) {
735
745
  return DEFAULT_CELL_HEIGHT;
736
746
  }
737
747
  const fontSize = computeTextFontSizeInPixels(cell.style);
738
- const multiLineText = cell.content.split(NEWLINE);
739
- return computeTextLinesHeight(fontSize, multiLineText.length) + 2 * PADDING_AUTORESIZE_VERTICAL;
748
+ // the number of lines should be computed from the formula result, but it's not evaluated at this point
749
+ const numberOfLines = cell.isFormula ? 1 : cell.content.split(NEWLINE).length;
750
+ return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
740
751
  }
741
752
  function computeTextWidth(context, text, style) {
742
753
  context.save();
@@ -1088,6 +1099,8 @@ function replaceSpecialSpaces(text) {
1088
1099
  return text;
1089
1100
  }
1090
1101
 
1102
+ const RBA_REGEX = /rgba?\(|\s+|\)/gi;
1103
+ const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
1091
1104
  const colors$1 = [
1092
1105
  "#eb6d00",
1093
1106
  "#0074d9",
@@ -1113,7 +1126,10 @@ function colorNumberString(color) {
1113
1126
  }
1114
1127
  /**
1115
1128
  * Converts any CSS color value to a standardized hex6 value.
1116
- * Accepts: hex3, hex6, hex8 and rgb (rgba is not supported)
1129
+ * Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
1130
+ *
1131
+ * [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
1132
+ * with r,g,b ∈ [0, 255] and a ∈ [0, 1]
1117
1133
  *
1118
1134
  * toHex("#ABC")
1119
1135
  * >> "#AABBCC"
@@ -1124,27 +1140,31 @@ function colorNumberString(color) {
1124
1140
  * toHex("rgb(30, 80, 16)")
1125
1141
  * >> "#1E5010"
1126
1142
  *
1143
+ * * toHex("rgb(30, 80, 16, 0.5)")
1144
+ * >> "#1E501080"
1145
+ *
1127
1146
  */
1128
1147
  function toHex(color) {
1129
- if (color.includes("rgba")) {
1130
- throw new Error(`rgba() conversion currently not supported: ${color}`);
1131
- }
1132
- if (color.includes("rgb")) {
1133
- return rgbToHex6(color);
1148
+ let hexColor = color;
1149
+ if (color.startsWith("rgb")) {
1150
+ hexColor = rgbaStringToHex(color);
1134
1151
  }
1135
- color = color.replace("#", "").toUpperCase();
1136
- if (color.length === 3 || color.length === 4) {
1137
- color = color.split("").reduce((acc, h) => acc + h + h, "");
1152
+ else {
1153
+ hexColor = color.replace("#", "").toUpperCase();
1154
+ if (hexColor.length === 3 || hexColor.length === 4) {
1155
+ hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
1156
+ }
1157
+ hexColor = `#${hexColor}`;
1138
1158
  }
1139
- if (color.replace(/[a-f0-9]/gi, "") !== "") {
1140
- throw new Error("invalid color");
1159
+ if (!hexColor.match(HEX_MATCH)) {
1160
+ throw new Error(`invalid color input: ${color}`);
1141
1161
  }
1142
- return "#" + color;
1162
+ return hexColor;
1143
1163
  }
1144
1164
  function isColorValid(color) {
1145
1165
  try {
1146
- const { r, g, b, a } = colorToRGBA(color);
1147
- return (isColorValueValid(r) && isColorValueValid(g) && isColorValueValid(b) && isColorValueValid(a));
1166
+ toHex(color);
1167
+ return true;
1148
1168
  }
1149
1169
  catch (error) {
1150
1170
  return false;
@@ -1177,15 +1197,29 @@ function relativeLuminance(color) {
1177
1197
  /**
1178
1198
  * Convert a CSS rgb color string to a standardized hex6 color value.
1179
1199
  *
1180
- * rgbToHex6("rgb(30, 80, 16)")
1200
+ * rgbaStringToHex("rgb(30, 80, 16)")
1181
1201
  * >> "#1E5010"
1202
+ *
1203
+ * rgbaStringToHex("rgba(30, 80, 16, 0.5)")
1204
+ * >> "#1E501080"
1205
+ *
1206
+ * DOES NOT SUPPORT NON INTEGER RGB VALUES
1182
1207
  */
1183
- function rgbToHex6(color) {
1184
- return ("#" +
1185
- concat(color
1186
- .slice(4, -1)
1187
- .split(",")
1188
- .map((valueString) => parseInt(valueString, 10).toString(16).padStart(2, "0"))).toUpperCase());
1208
+ function rgbaStringToHex(color) {
1209
+ const stringVals = color.replace(RBA_REGEX, "").split(",");
1210
+ let alphaHex = 255;
1211
+ if (stringVals.length !== 3 && stringVals.length !== 4) {
1212
+ throw new Error("invalid color");
1213
+ }
1214
+ else if (stringVals.length === 4) {
1215
+ const alpha = parseFloat(stringVals.pop() || "1");
1216
+ alphaHex = Math.round((alpha || 1) * 255);
1217
+ }
1218
+ const vals = stringVals.map((val) => parseInt(val, 10));
1219
+ if (alphaHex !== 255) {
1220
+ vals.push(alphaHex);
1221
+ }
1222
+ return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
1189
1223
  }
1190
1224
  /**
1191
1225
  * RGBA to HEX representation (#RRGGBBAA).
@@ -1207,7 +1241,7 @@ function rgbaToHex(rgba) {
1207
1241
  a = "0" + a;
1208
1242
  if (a === "ff")
1209
1243
  a = "";
1210
- return "#" + r + g + b + a;
1244
+ return ("#" + r + g + b + a).toUpperCase();
1211
1245
  }
1212
1246
  /**
1213
1247
  * Color string to RGBA representation
@@ -1328,6 +1362,9 @@ function rgbaToHSLA(rgba) {
1328
1362
  s = +(s * 100).toFixed(1);
1329
1363
  l = +(l * 100).toFixed(1);
1330
1364
  return { a: rgba.a, h, s, l };
1365
+ }
1366
+ function isSameColor(color1, color2) {
1367
+ return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
1331
1368
  }
1332
1369
 
1333
1370
  /** Reference of a cell (eg. A1, $B$5) */
@@ -1479,7 +1516,7 @@ function scrollDelay(value) {
1479
1516
  * formula, commas are used to separate arguments
1480
1517
  * - it does not support % symbol, in formulas % is an operator
1481
1518
  */
1482
- const formulaNumberRegexp = /^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+/;
1519
+ const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
1483
1520
  const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
1484
1521
  const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
1485
1522
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -3088,6 +3125,7 @@ const CHART_PADDING_RATIO = 0.02;
3088
3125
  const LINE_HEIGHT = 1.2;
3089
3126
  css /* scss */ `
3090
3127
  div.o-scorecard {
3128
+ font-family: ${DEFAULT_FONT};
3091
3129
  user-select: none;
3092
3130
  background-color: white;
3093
3131
  display: flex;
@@ -5154,6 +5192,11 @@ class Popover extends Component {
5154
5192
  this.currentPosition = newPosition;
5155
5193
  });
5156
5194
  }
5195
+ get popoverStyle() {
5196
+ return cssPropertiesToCss({
5197
+ "z-index": `${this.props.zIndex}`,
5198
+ });
5199
+ }
5157
5200
  }
5158
5201
  Popover.template = "o-spreadsheet-Popover";
5159
5202
  Popover.defaultProps = {
@@ -5162,6 +5205,7 @@ Popover.defaultProps = {
5162
5205
  onMouseWheel: () => { },
5163
5206
  onPopoverMoved: () => { },
5164
5207
  onPopoverHidden: () => { },
5208
+ zIndex: ComponentsImportance.Popover,
5165
5209
  };
5166
5210
  Popover.props = {
5167
5211
  anchorRect: Object,
@@ -5173,6 +5217,7 @@ Popover.props = {
5173
5217
  onMouseWheel: { type: Function, optional: true },
5174
5218
  onPopoverHidden: { type: Function, optional: true },
5175
5219
  onPopoverMoved: { type: Function, optional: true },
5220
+ zIndex: { type: Number, optional: true },
5176
5221
  slots: Object,
5177
5222
  };
5178
5223
  class PopoverPositionContext {
@@ -5316,7 +5361,7 @@ css /* scss */ `
5316
5361
  align-items: center;
5317
5362
  box-sizing: border-box;
5318
5363
  height: ${MENU_ITEM_HEIGHT}px;
5319
- padding: 4px 16px;
5364
+ padding: ${MENU_ITEM_PADDING_VERTICAL}px ${MENU_ITEM_PADDING_HORIZONTAL}px;
5320
5365
  cursor: pointer;
5321
5366
  user-select: none;
5322
5367
 
@@ -5330,11 +5375,18 @@ css /* scss */ `
5330
5375
  display: flex;
5331
5376
  justify-content: space-between;
5332
5377
  }
5378
+
5333
5379
  .o-menu-item-icon {
5334
- margin-top: auto;
5335
- margin-bottom: auto;
5380
+ display: inline-block;
5381
+ margin-right: calc(${MENU_ITEM_PADDING_HORIZONTAL}px * 3 / 5);
5382
+ width: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
5383
+ line-height: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
5384
+
5385
+ .o-icon {
5386
+ color: ${ICONS_COLOR};
5387
+ }
5336
5388
  }
5337
- .o-icon {
5389
+ .o-menu-item-root {
5338
5390
  width: 10px;
5339
5391
  }
5340
5392
 
@@ -5375,24 +5427,30 @@ class Menu extends Component {
5375
5427
  }
5376
5428
  });
5377
5429
  }
5378
- get visibleMenuItems() {
5379
- return this.props.menuItems.filter((x) => x.isVisible(this.env));
5430
+ get menuItemsAndSeparators() {
5431
+ const menuItemsAndSeparators = [];
5432
+ for (let i = 0; i < this.props.menuItems.length; i++) {
5433
+ const menuItem = this.props.menuItems[i];
5434
+ if (menuItem.isVisible(this.env)) {
5435
+ menuItemsAndSeparators.push(menuItem);
5436
+ }
5437
+ if (menuItem.separator &&
5438
+ i !== this.props.menuItems.length - 1 && // no separator at the end
5439
+ menuItemsAndSeparators[menuItemsAndSeparators.length - 1] !== "separator" // no double separator
5440
+ ) {
5441
+ menuItemsAndSeparators.push("separator");
5442
+ }
5443
+ }
5444
+ if (menuItemsAndSeparators.length === 1 && menuItemsAndSeparators[0] === "separator") {
5445
+ return [];
5446
+ }
5447
+ return menuItemsAndSeparators;
5380
5448
  }
5381
5449
  get subMenuPosition() {
5382
5450
  const position = Object.assign({}, this.subMenu.position);
5383
5451
  position.y -= this.subMenu.scrollOffset || 0;
5384
5452
  return position;
5385
5453
  }
5386
- get menuHeight() {
5387
- const menuItems = this.visibleMenuItems;
5388
- let menuItemsHeight = this.getMenuItemsHeight(menuItems);
5389
- // We don't display separator at the end of a menu
5390
- if (menuItems[menuItems.length - 1].separator) {
5391
- menuItemsHeight -= MENU_SEPARATOR_HEIGHT;
5392
- }
5393
- const menuHeight = 2 * MENU_VERTICAL_PADDING + menuItemsHeight;
5394
- return this.props.maxHeight ? Math.min(menuHeight, this.props.maxHeight) : menuHeight;
5395
- }
5396
5454
  get popoverProps() {
5397
5455
  const isRoot = this.props.depth === 1;
5398
5456
  return {
@@ -5406,15 +5464,24 @@ class Menu extends Component {
5406
5464
  verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
5407
5465
  onPopoverHidden: () => this.closeSubMenu(),
5408
5466
  onPopoverMoved: () => this.closeSubMenu(),
5409
- maxHeight: this.menuHeight,
5410
5467
  };
5411
5468
  }
5469
+ get childrenHaveIcon() {
5470
+ return this.props.menuItems.some((menuItem) => !menuItem.icon && !!menuItem.isActive);
5471
+ }
5472
+ getIconName(menu) {
5473
+ var _a;
5474
+ if ((_a = menu.isActive) === null || _a === void 0 ? void 0 : _a.call(menu, this.env)) {
5475
+ return "o-spreadsheet-Icon.CHECK";
5476
+ }
5477
+ return "";
5478
+ }
5412
5479
  getColor(menu) {
5413
5480
  return menu.textColor ? `color: ${menu.textColor}` : undefined;
5414
5481
  }
5415
5482
  async activateMenu(menu) {
5416
5483
  var _a, _b, _c;
5417
- const result = await ((_a = menu.action) === null || _a === void 0 ? void 0 : _a.call(menu, this.env));
5484
+ const result = await ((_a = menu.execute) === null || _a === void 0 ? void 0 : _a.call(menu, this.env));
5418
5485
  this.close();
5419
5486
  (_c = (_b = this.props).onMenuClicked) === null || _c === void 0 ? void 0 : _c.call(_b, { detail: result });
5420
5487
  }
@@ -5422,14 +5489,6 @@ class Menu extends Component {
5422
5489
  this.closeSubMenu();
5423
5490
  this.props.onClose();
5424
5491
  }
5425
- /**
5426
- * Return the number of pixels between the top of the menu
5427
- * and the menu item at a given index.
5428
- */
5429
- subMenuVerticalPosition(menuIndex) {
5430
- const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
5431
- return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
5432
- }
5433
5492
  onExternalClick(ev) {
5434
5493
  // Don't close a root menu when clicked to open the submenus.
5435
5494
  const el = this.menuRef.el;
@@ -5439,15 +5498,11 @@ class Menu extends Component {
5439
5498
  ev.closedMenuId = this.props.menuId;
5440
5499
  this.close();
5441
5500
  }
5442
- getMenuItemsHeight(menuItems) {
5443
- const numberOfSeparators = menuItems.filter((m) => m.separator).length;
5444
- return MENU_ITEM_HEIGHT * menuItems.length + MENU_SEPARATOR_HEIGHT * numberOfSeparators;
5445
- }
5446
5501
  getName(menu) {
5447
5502
  return menu.name(this.env);
5448
5503
  }
5449
5504
  isRoot(menu) {
5450
- return !menu.action;
5505
+ return !menu.execute;
5451
5506
  }
5452
5507
  isEnabled(menu) {
5453
5508
  if (menu.isEnabled(this.env)) {
@@ -5462,8 +5517,11 @@ class Menu extends Component {
5462
5517
  * If the given menu is not disabled, open it's submenu at the
5463
5518
  * correct position according to available surrounding space.
5464
5519
  */
5465
- openSubMenu(menu, menuIndex) {
5466
- const y = this.subMenuVerticalPosition(menuIndex);
5520
+ openSubMenu(menu, menuIndex, ev) {
5521
+ const parentMenuEl = ev.currentTarget;
5522
+ if (!parentMenuEl)
5523
+ return;
5524
+ const y = parentMenuEl.getBoundingClientRect().top;
5467
5525
  this.subMenu.position = {
5468
5526
  x: this.position.x + this.props.depth * MENU_WIDTH,
5469
5527
  y: y - (this.subMenu.scrollOffset || 0),
@@ -5480,20 +5538,20 @@ class Menu extends Component {
5480
5538
  this.subMenu.isOpen = false;
5481
5539
  this.subMenu.parentMenu = undefined;
5482
5540
  }
5483
- onClickMenu(menu, menuIndex) {
5541
+ onClickMenu(menu, menuIndex, ev) {
5484
5542
  if (this.isEnabled(menu)) {
5485
5543
  if (this.isRoot(menu)) {
5486
- this.openSubMenu(menu, menuIndex);
5544
+ this.openSubMenu(menu, menuIndex, ev);
5487
5545
  }
5488
5546
  else {
5489
5547
  this.activateMenu(menu);
5490
5548
  }
5491
5549
  }
5492
5550
  }
5493
- onMouseOver(menu, position) {
5494
- if (menu.isEnabled(this.env)) {
5551
+ onMouseOver(menu, position, ev) {
5552
+ if (this.isEnabled(menu)) {
5495
5553
  if (this.isRoot(menu)) {
5496
- this.openSubMenu(menu, position);
5554
+ this.openSubMenu(menu, position, ev);
5497
5555
  }
5498
5556
  else {
5499
5557
  this.closeSubMenu();
@@ -5628,11 +5686,82 @@ LinkDisplay.props = {
5628
5686
  onClosed: { type: Function, optional: true },
5629
5687
  };
5630
5688
 
5631
- function createMenu(menuItems) {
5632
- return menuItems.map(createMenuItem).sort((a, b) => a.sequence - b.sequence);
5689
+ const linkSheet = {
5690
+ name: _lt("Link sheet"),
5691
+ children: [
5692
+ (env) => {
5693
+ const sheets = env.model.getters
5694
+ .getSheetIds()
5695
+ .map((sheetId) => env.model.getters.getSheet(sheetId));
5696
+ return sheets.map((sheet) => ({
5697
+ id: sheet.id,
5698
+ name: sheet.name,
5699
+ execute: () => markdownLink(sheet.name, buildSheetLink(sheet.id)),
5700
+ }));
5701
+ },
5702
+ ],
5703
+ };
5704
+ const deleteSheet = {
5705
+ name: _lt("Delete"),
5706
+ isVisible: (env) => {
5707
+ return env.model.getters.getSheetIds().length > 1;
5708
+ },
5709
+ execute: (env) => env.askConfirmation(_lt("Are you sure you want to delete this sheet ?"), () => {
5710
+ env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
5711
+ }),
5712
+ };
5713
+ const duplicateSheet = {
5714
+ name: _lt("Duplicate"),
5715
+ execute: (env) => {
5716
+ const sheetIdFrom = env.model.getters.getActiveSheetId();
5717
+ const sheetIdTo = env.model.uuidGenerator.uuidv4();
5718
+ env.model.dispatch("DUPLICATE_SHEET", {
5719
+ sheetId: sheetIdFrom,
5720
+ sheetIdTo,
5721
+ });
5722
+ env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
5723
+ },
5724
+ };
5725
+ const renameSheet = (args) => {
5726
+ return {
5727
+ name: _lt("Rename"),
5728
+ execute: args.renameSheetCallback,
5729
+ };
5730
+ };
5731
+ const sheetMoveRight = {
5732
+ name: _lt("Move right"),
5733
+ isVisible: (env) => {
5734
+ const sheetId = env.model.getters.getActiveSheetId();
5735
+ const sheetIds = env.model.getters.getVisibleSheetIds();
5736
+ return sheetIds.indexOf(sheetId) !== sheetIds.length - 1;
5737
+ },
5738
+ execute: (env) => env.model.dispatch("MOVE_SHEET", {
5739
+ sheetId: env.model.getters.getActiveSheetId(),
5740
+ delta: 1,
5741
+ }),
5742
+ };
5743
+ const sheetMoveLeft = {
5744
+ name: _lt("Move left"),
5745
+ isVisible: (env) => {
5746
+ const sheetId = env.model.getters.getActiveSheetId();
5747
+ return env.model.getters.getVisibleSheetIds()[0] !== sheetId;
5748
+ },
5749
+ execute: (env) => env.model.dispatch("MOVE_SHEET", {
5750
+ sheetId: env.model.getters.getActiveSheetId(),
5751
+ delta: -1,
5752
+ }),
5753
+ };
5754
+ const hideSheet = {
5755
+ name: _lt("Hide sheet"),
5756
+ isVisible: (env) => env.model.getters.getVisibleSheetIds().length !== 1,
5757
+ execute: (env) => env.model.dispatch("HIDE_SHEET", { sheetId: env.model.getters.getActiveSheetId() }),
5758
+ };
5759
+
5760
+ function createActions(menuItems) {
5761
+ return menuItems.map(createAction).sort((a, b) => a.sequence - b.sequence);
5633
5762
  }
5634
5763
  const uuidGenerator$1 = new UuidGenerator();
5635
- function createMenuItem(item) {
5764
+ function createAction(item) {
5636
5765
  const name = item.name;
5637
5766
  const children = item.children;
5638
5767
  return {
@@ -5640,23 +5769,25 @@ function createMenuItem(item) {
5640
5769
  name: typeof name === "function" ? name : () => name,
5641
5770
  isVisible: item.isVisible ? item.isVisible : () => true,
5642
5771
  isEnabled: item.isEnabled ? item.isEnabled : () => true,
5643
- action: item.action,
5772
+ isActive: item.isActive,
5773
+ execute: item.execute,
5644
5774
  children: children
5645
5775
  ? (env) => {
5646
5776
  return children
5647
5777
  .map((child) => (typeof child === "function" ? child(env) : child))
5648
5778
  .flat()
5649
- .map(createMenuItem);
5779
+ .map(createAction);
5650
5780
  }
5651
5781
  : () => [],
5652
5782
  isReadonlyAllowed: item.isReadonlyAllowed || false,
5653
5783
  separator: item.separator || false,
5654
- icon: item.icon,
5784
+ icon: item.icon || "",
5655
5785
  description: item.description || "",
5656
5786
  textColor: item.textColor,
5657
5787
  sequence: item.sequence || 0,
5658
5788
  };
5659
- }
5789
+ }
5790
+
5660
5791
  /**
5661
5792
  * The class Registry is extended in order to add the function addChild
5662
5793
  *
@@ -5703,7 +5834,7 @@ class MenuItemRegistry extends Registry {
5703
5834
  return this;
5704
5835
  }
5705
5836
  getMenuItems() {
5706
- return createMenu(this.getAll());
5837
+ return createActions(this.getAll());
5707
5838
  }
5708
5839
  }
5709
5840
 
@@ -5711,20 +5842,9 @@ class MenuItemRegistry extends Registry {
5711
5842
  // Link Menu Registry
5712
5843
  //------------------------------------------------------------------------------
5713
5844
  const linkMenuRegistry = new MenuItemRegistry();
5714
- linkMenuRegistry
5715
- .add("sheet", {
5716
- name: _lt("Link sheet"),
5845
+ linkMenuRegistry.add("sheet", {
5846
+ ...linkSheet,
5717
5847
  sequence: 10,
5718
- })
5719
- .addChild("sheet_list", ["sheet"], (env) => {
5720
- const sheets = env.model.getters
5721
- .getSheetIds()
5722
- .map((sheetId) => env.model.getters.getSheet(sheetId));
5723
- return sheets.map((sheet) => ({
5724
- id: sheet.id,
5725
- name: sheet.name,
5726
- action: () => markdownLink(sheet.name, buildSheetLink(sheet.id)),
5727
- }));
5728
5848
  });
5729
5849
 
5730
5850
  const MENU_OFFSET_X = 320;
@@ -6070,8 +6190,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
6070
6190
  const dataSets = [];
6071
6191
  for (const sheetXC of dataSetsString) {
6072
6192
  const dataRange = getters.getRangeFromSheetXC(sheetId, sheetXC);
6073
- const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName } = dataRange;
6074
- if (invalidSheetName) {
6193
+ const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName, invalidXc } = dataRange;
6194
+ if (invalidSheetName || invalidXc) {
6075
6195
  continue;
6076
6196
  }
6077
6197
  // It's a rectangle. We treat all columns (arbitrary) as different data series.
@@ -6096,14 +6216,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
6096
6216
  : undefined));
6097
6217
  }
6098
6218
  }
6099
- else if (zone.left === zone.right && zone.top === zone.bottom) {
6100
- // A single cell. If it's only the title, the dataset is not added.
6101
- if (!dataSetsHaveTitle) {
6102
- dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
6103
- }
6104
- }
6105
6219
  else {
6106
- /* 1 row or 1 column */
6220
+ /* 1 cell, 1 row or 1 column */
6107
6221
  dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
6108
6222
  ? {
6109
6223
  top: zone.top,
@@ -6157,6 +6271,18 @@ function toExcelDataset(getters, ds) {
6157
6271
  range: getters.getRangeString(dataRange, "forceSheetReference"),
6158
6272
  };
6159
6273
  }
6274
+ function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
6275
+ if (!labelRange)
6276
+ return undefined;
6277
+ let zone = {
6278
+ ...labelRange.zone,
6279
+ };
6280
+ if (shouldRemoveFirstLabel && labelRange.zone.bottom > labelRange.zone.top) {
6281
+ zone.top = zone.top + 1;
6282
+ }
6283
+ const range = labelRange.clone({ zone });
6284
+ return getters.getRangeString(range, "forceSheetReference");
6285
+ }
6160
6286
  /**
6161
6287
  * Transform a chart definition which supports dataSets (dataSets and LabelRange)
6162
6288
  * with an executed command
@@ -6241,6 +6367,20 @@ function checkLabelRange(definition) {
6241
6367
  }
6242
6368
  return 0 /* CommandResult.Success */;
6243
6369
  }
6370
+ function shouldRemoveFirstLabel(labelRange, dataset, dataSetsHaveTitle) {
6371
+ if (!dataSetsHaveTitle)
6372
+ return false;
6373
+ if (!labelRange)
6374
+ return false;
6375
+ if (!dataset)
6376
+ return true;
6377
+ const datasetLength = getZoneArea(dataset.dataRange.zone);
6378
+ const labelLength = getZoneArea(labelRange.zone);
6379
+ if (labelLength < datasetLength) {
6380
+ return false;
6381
+ }
6382
+ return true;
6383
+ }
6244
6384
  // ---------------------------------------------------------------------------
6245
6385
  // Scorecard
6246
6386
  // ---------------------------------------------------------------------------
@@ -6368,18 +6508,6 @@ const ChartTerms = {
6368
6508
  [43 /* CommandResult.GaugeUpperInflectionPointNaN */]: _lt("The upper inflection point value must be a number"),
6369
6509
  },
6370
6510
  };
6371
- const NumberFormatTerms = {
6372
- Automatic: _lt("Automatic"),
6373
- Number: _lt("Number"),
6374
- Percent: _lt("Percent"),
6375
- Currency: _lt("Currency"),
6376
- CurrencyRounded: _lt("Currency rounded"),
6377
- Date: _lt("Date"),
6378
- Time: _lt("Time"),
6379
- DateTime: _lt("Date time"),
6380
- Duration: _lt("Duration"),
6381
- CustomCurrency: _lt("Custom currency"),
6382
- };
6383
6511
  const CustomCurrencyTerms = {
6384
6512
  Custom: _lt("Custom"),
6385
6513
  };
@@ -6610,6 +6738,7 @@ class BarChart extends AbstractChart {
6610
6738
  this.legendPosition = definition.legendPosition;
6611
6739
  this.stacked = definition.stacked;
6612
6740
  this.aggregated = definition.aggregated;
6741
+ this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
6613
6742
  }
6614
6743
  static transformDefinition(definition, executed) {
6615
6744
  return transformChartDefinitionWithDataSetsWithZone(definition, executed);
@@ -6677,11 +6806,13 @@ class BarChart extends AbstractChart {
6677
6806
  const dataSets = this.dataSets
6678
6807
  .map((ds) => toExcelDataset(this.getters, ds))
6679
6808
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
6809
+ const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
6680
6810
  return {
6681
6811
  ...this.getDefinition(),
6682
6812
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
6683
6813
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
6684
6814
  dataSets,
6815
+ labelRange,
6685
6816
  };
6686
6817
  }
6687
6818
  updateRanges(applyChange) {
@@ -6749,6 +6880,11 @@ function createBarChartRuntime(chart, getters) {
6749
6880
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
6750
6881
  let labels = labelValues.formattedValues;
6751
6882
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
6883
+ if (chart.dataSetsHaveTitle &&
6884
+ dataSetsValues[0] &&
6885
+ labels.length > dataSetsValues[0].data.length) {
6886
+ labels.shift();
6887
+ }
6752
6888
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
6753
6889
  if (chart.aggregated) {
6754
6890
  ({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
@@ -7171,6 +7307,7 @@ class LineChart extends AbstractChart {
7171
7307
  this.labelsAsText = definition.labelsAsText;
7172
7308
  this.stacked = definition.stacked;
7173
7309
  this.aggregated = definition.aggregated;
7310
+ this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
7174
7311
  }
7175
7312
  static validateChartDefinition(validator, definition) {
7176
7313
  return validator.checkValidations(definition, checkDataset, checkLabelRange);
@@ -7238,11 +7375,13 @@ class LineChart extends AbstractChart {
7238
7375
  const dataSets = this.dataSets
7239
7376
  .map((ds) => toExcelDataset(this.getters, ds))
7240
7377
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
7378
+ const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
7241
7379
  return {
7242
7380
  ...this.getDefinition(),
7243
7381
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
7244
7382
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
7245
7383
  dataSets,
7384
+ labelRange,
7246
7385
  };
7247
7386
  }
7248
7387
  copyForSheetId(sheetId) {
@@ -7380,6 +7519,11 @@ function createLineChartRuntime(chart, getters) {
7380
7519
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
7381
7520
  let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
7382
7521
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
7522
+ if (chart.dataSetsHaveTitle &&
7523
+ dataSetsValues[0] &&
7524
+ labels.length > dataSetsValues[0].data.length) {
7525
+ labels.shift();
7526
+ }
7383
7527
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
7384
7528
  if (axisType === "time") {
7385
7529
  ({ labels, dataSetsValues } = fixEmptyLabelsForDateCharts(labels, dataSetsValues));
@@ -7438,6 +7582,7 @@ class PieChart extends AbstractChart {
7438
7582
  this.background = definition.background;
7439
7583
  this.legendPosition = definition.legendPosition;
7440
7584
  this.aggregated = definition.aggregated;
7585
+ this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
7441
7586
  }
7442
7587
  static transformDefinition(definition, executed) {
7443
7588
  return transformChartDefinitionWithDataSetsWithZone(definition, executed);
@@ -7501,12 +7646,14 @@ class PieChart extends AbstractChart {
7501
7646
  const dataSets = this.dataSets
7502
7647
  .map((ds) => toExcelDataset(this.getters, ds))
7503
7648
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
7649
+ const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
7504
7650
  return {
7505
7651
  ...this.getDefinition(),
7506
7652
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
7507
7653
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
7508
7654
  verticalAxisPosition: "left",
7509
7655
  dataSets,
7656
+ labelRange,
7510
7657
  };
7511
7658
  }
7512
7659
  updateRanges(applyChange) {
@@ -7552,6 +7699,11 @@ function createPieChartRuntime(chart, getters) {
7552
7699
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
7553
7700
  let labels = labelValues.formattedValues;
7554
7701
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
7702
+ if (chart.dataSetsHaveTitle &&
7703
+ dataSetsValues[0] &&
7704
+ labels.length > dataSetsValues[0].data.length) {
7705
+ labels.shift();
7706
+ }
7555
7707
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
7556
7708
  if (chart.aggregated) {
7557
7709
  ({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
@@ -7899,7 +8051,7 @@ function getChartMenu(figureId, onFigureDeleted, env) {
7899
8051
  id: "edit",
7900
8052
  name: _lt("Edit"),
7901
8053
  sequence: 1,
7902
- action: () => {
8054
+ execute: () => {
7903
8055
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
7904
8056
  env.openSidePanel("ChartPanel");
7905
8057
  },
@@ -7908,7 +8060,7 @@ function getChartMenu(figureId, onFigureDeleted, env) {
7908
8060
  getCutMenuItem(figureId, env),
7909
8061
  getDeleteMenuItem(figureId, onFigureDeleted, env),
7910
8062
  ];
7911
- return createMenu(menuItemSpecs);
8063
+ return createActions(menuItemSpecs);
7912
8064
  }
7913
8065
  function getImageMenuRegistry(figureId, onFigureDeleted, env) {
7914
8066
  const menuItemSpecs = [
@@ -7918,7 +8070,7 @@ function getImageMenuRegistry(figureId, onFigureDeleted, env) {
7918
8070
  id: "reset_size",
7919
8071
  name: _lt("Reset size"),
7920
8072
  sequence: 4,
7921
- action: () => {
8073
+ execute: () => {
7922
8074
  const size = env.model.getters.getImageSize(figureId);
7923
8075
  const { height, width } = getMaxFigureSize(env.model.getters, size);
7924
8076
  env.model.dispatch("UPDATE_FIGURE", {
@@ -7931,7 +8083,7 @@ function getImageMenuRegistry(figureId, onFigureDeleted, env) {
7931
8083
  },
7932
8084
  getDeleteMenuItem(figureId, onFigureDeleted, env),
7933
8085
  ];
7934
- return createMenu(menuItemSpecs);
8086
+ return createActions(menuItemSpecs);
7935
8087
  }
7936
8088
  function getCopyMenuItem(figureId, env) {
7937
8089
  return {
@@ -7939,7 +8091,7 @@ function getCopyMenuItem(figureId, env) {
7939
8091
  name: _lt("Copy"),
7940
8092
  sequence: 2,
7941
8093
  description: "Ctrl+C",
7942
- action: async () => {
8094
+ execute: async () => {
7943
8095
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
7944
8096
  env.model.dispatch("COPY");
7945
8097
  await env.clipboard.write(env.model.getters.getClipboardContent());
@@ -7952,7 +8104,7 @@ function getCutMenuItem(figureId, env) {
7952
8104
  name: _lt("Cut"),
7953
8105
  sequence: 3,
7954
8106
  description: "Ctrl+X",
7955
- action: async () => {
8107
+ execute: async () => {
7956
8108
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
7957
8109
  env.model.dispatch("CUT");
7958
8110
  await env.clipboard.write(env.model.getters.getClipboardContent());
@@ -7964,7 +8116,7 @@ function getDeleteMenuItem(figureId, onFigureDeleted, env) {
7964
8116
  id: "delete",
7965
8117
  name: _lt("Delete"),
7966
8118
  sequence: 10,
7967
- action: () => {
8119
+ execute: () => {
7968
8120
  env.model.dispatch("DELETE_FIGURE", {
7969
8121
  sheetId: env.model.getters.getActiveSheetId(),
7970
8122
  id: figureId,
@@ -8071,6 +8223,22 @@ function inverseUnhideColumnsRows(cmd) {
8071
8223
  ];
8072
8224
  }
8073
8225
 
8226
+ const AddMergeInteractiveContent = {
8227
+ MergeIsDestructive: _lt("Merging these cells will only preserve the top-leftmost value. Merge anyway?"),
8228
+ MergeInFilter: _lt("You can't merge cells inside of an existing filter."),
8229
+ };
8230
+ function interactiveAddMerge(env, sheetId, target) {
8231
+ const result = env.model.dispatch("ADD_MERGE", { sheetId, target });
8232
+ if (result.isCancelledBecause(80 /* CommandResult.MergeInFilter */)) {
8233
+ env.raiseError(AddMergeInteractiveContent.MergeInFilter);
8234
+ }
8235
+ else if (result.isCancelledBecause(3 /* CommandResult.MergeIsDestructive */)) {
8236
+ env.askConfirmation(AddMergeInteractiveContent.MergeIsDestructive, () => {
8237
+ env.model.dispatch("ADD_MERGE", { sheetId, target, force: true });
8238
+ });
8239
+ }
8240
+ }
8241
+
8074
8242
  /**
8075
8243
  * Create a function used to create a Chart based on the definition
8076
8244
  */
@@ -8187,7 +8355,6 @@ function getSmartChartDefinition(zone, getters) {
8187
8355
  labelRangeXc = zoneToXc({
8188
8356
  ...zone,
8189
8357
  right: zone.left,
8190
- top: dataSetsHaveTitle ? zone.top + 1 : zone.top,
8191
8358
  });
8192
8359
  }
8193
8360
  // Only display legend for several datasets.
@@ -8427,9 +8594,9 @@ const CUT_ACTION = async (env) => {
8427
8594
  interactiveCut(env);
8428
8595
  await env.clipboard.write(env.model.getters.getClipboardContent());
8429
8596
  };
8430
- const PASTE_ACTION = async (env) => paste(env);
8431
- const PASTE_VALUE_ACTION = async (env) => paste(env, "onlyValue");
8432
- async function paste(env, pasteOption) {
8597
+ const PASTE_ACTION = async (env) => paste$1(env);
8598
+ const PASTE_VALUE_ACTION = async (env) => paste$1(env, "onlyValue");
8599
+ async function paste$1(env, pasteOption) {
8433
8600
  const spreadsheetClipboard = env.model.getters.getClipboardTextContent();
8434
8601
  const osClipboard = await env.clipboard.readText();
8435
8602
  switch (osClipboard.status) {
@@ -8983,365 +9150,159 @@ const IS_ONLY_ONE_RANGE = (env) => {
8983
9150
  return env.model.getters.getSelectedZones().length === 1;
8984
9151
  };
8985
9152
 
8986
- //------------------------------------------------------------------------------
8987
- // Context Menu Registry
8988
- //------------------------------------------------------------------------------
8989
- const cellMenuRegistry = new MenuItemRegistry();
8990
- cellMenuRegistry
8991
- .add("cut", {
8992
- name: _lt("Cut"),
8993
- description: "Ctrl+X",
8994
- sequence: 10,
8995
- action: CUT_ACTION,
8996
- })
8997
- .add("copy", {
9153
+ const undo = {
9154
+ name: _lt("Undo"),
9155
+ description: "Ctrl+Z",
9156
+ execute: UNDO_ACTION,
9157
+ isEnabled: (env) => env.model.getters.canUndo(),
9158
+ icon: "o-spreadsheet-Icon.UNDO",
9159
+ };
9160
+ const redo = {
9161
+ name: _lt("Redo"),
9162
+ description: "Ctrl+Y",
9163
+ execute: REDO_ACTION,
9164
+ isEnabled: (env) => env.model.getters.canRedo(),
9165
+ icon: "o-spreadsheet-Icon.REDO",
9166
+ };
9167
+ const copy = {
8998
9168
  name: _lt("Copy"),
8999
9169
  description: "Ctrl+C",
9000
- sequence: 20,
9001
9170
  isReadonlyAllowed: true,
9002
- action: COPY_ACTION,
9003
- })
9004
- .add("paste", {
9005
- name: _lt("Paste"),
9006
- description: "Ctrl+V",
9007
- sequence: 30,
9008
- action: PASTE_ACTION,
9009
- })
9010
- .add("paste_special", {
9011
- name: _lt("Paste special"),
9012
- sequence: 40,
9013
- separator: true,
9014
- isVisible: IS_NOT_CUT_OPERATION,
9015
- })
9016
- .addChild("paste_value_only", ["paste_special"], {
9017
- name: _lt("Paste values only"),
9018
- sequence: 10,
9019
- action: PASTE_VALUE_ACTION,
9020
- })
9021
- .addChild("paste_format_only", ["paste_special"], {
9022
- name: _lt("Paste format only"),
9023
- sequence: 20,
9024
- action: PASTE_FORMAT_ACTION,
9025
- })
9026
- .add("add_row_before", {
9027
- name: CELL_INSERT_ROWS_BEFORE_NAME,
9028
- sequence: 70,
9029
- action: INSERT_ROWS_BEFORE_ACTION,
9030
- isVisible: IS_ONLY_ONE_RANGE,
9031
- })
9032
- .add("add_column_before", {
9033
- name: CELL_INSERT_COLUMNS_BEFORE_NAME,
9034
- sequence: 90,
9035
- action: INSERT_COLUMNS_BEFORE_ACTION,
9036
- isVisible: IS_ONLY_ONE_RANGE,
9037
- })
9038
- .add("insert_cell", {
9039
- name: _lt("Insert cells"),
9040
- sequence: 100,
9041
- isVisible: IS_ONLY_ONE_RANGE,
9042
- separator: true,
9043
- })
9044
- .addChild("insert_cell_down", ["insert_cell"], {
9045
- name: _lt("Shift down"),
9046
- sequence: 10,
9047
- action: INSERT_CELL_SHIFT_DOWN,
9048
- })
9049
- .addChild("insert_cell_right", ["insert_cell"], {
9050
- name: _lt("Shift right"),
9051
- sequence: 20,
9052
- action: INSERT_CELL_SHIFT_RIGHT,
9053
- })
9054
- .add("delete_row", {
9055
- name: REMOVE_ROWS_NAME,
9056
- sequence: 110,
9057
- action: REMOVE_ROWS_ACTION,
9058
- isVisible: IS_ONLY_ONE_RANGE,
9059
- })
9060
- .add("delete_column", {
9061
- name: REMOVE_COLUMNS_NAME,
9062
- sequence: 120,
9063
- action: REMOVE_COLUMNS_ACTION,
9064
- isVisible: IS_ONLY_ONE_RANGE,
9065
- })
9066
- .add("delete_cell", {
9067
- name: _lt("Delete cells"),
9068
- sequence: 130,
9069
- isVisible: IS_ONLY_ONE_RANGE,
9070
- })
9071
- .addChild("delete_cell_up", ["delete_cell"], {
9072
- name: _lt("Shift up"),
9073
- sequence: 10,
9074
- action: DELETE_CELL_SHIFT_UP,
9075
- })
9076
- .addChild("delete_cell_down", ["delete_cell"], {
9077
- name: _lt("Shift left"),
9078
- sequence: 20,
9079
- action: DELETE_CELL_SHIFT_LEFT,
9080
- })
9081
- .add("insert_link", {
9082
- name: _lt("Insert link"),
9083
- separator: true,
9084
- sequence: 150,
9085
- action: INSERT_LINK,
9086
- });
9087
-
9088
- const colMenuRegistry = new MenuItemRegistry();
9089
- colMenuRegistry
9090
- .add("cut", {
9171
+ execute: COPY_ACTION,
9172
+ };
9173
+ const cut = {
9091
9174
  name: _lt("Cut"),
9092
9175
  description: "Ctrl+X",
9093
- sequence: 10,
9094
- action: CUT_ACTION,
9095
- })
9096
- .add("copy", {
9097
- name: _lt("Copy"),
9098
- description: "Ctrl+C",
9099
- sequence: 20,
9100
- isReadonlyAllowed: true,
9101
- action: COPY_ACTION,
9102
- })
9103
- .add("paste", {
9176
+ execute: CUT_ACTION,
9177
+ };
9178
+ const paste = {
9104
9179
  name: _lt("Paste"),
9105
9180
  description: "Ctrl+V",
9106
- sequence: 30,
9107
- action: PASTE_ACTION,
9108
- })
9109
- .add("paste_special", {
9181
+ execute: PASTE_ACTION,
9182
+ };
9183
+ const pasteSpecial = {
9110
9184
  name: _lt("Paste special"),
9111
- sequence: 40,
9112
- separator: true,
9113
9185
  isVisible: IS_NOT_CUT_OPERATION,
9114
- })
9115
- .addChild("paste_value_only", ["paste_special"], {
9186
+ };
9187
+ const pasteSpecialValue = {
9116
9188
  name: _lt("Paste value only"),
9117
- sequence: 10,
9118
- action: PASTE_VALUE_ACTION,
9119
- })
9120
- .addChild("paste_format_only", ["paste_special"], {
9189
+ execute: PASTE_VALUE_ACTION,
9190
+ };
9191
+ const pasteSpecialFormat = {
9121
9192
  name: _lt("Paste format only"),
9122
- sequence: 20,
9123
- action: PASTE_FORMAT_ACTION,
9124
- })
9125
- .add("sort_columns", {
9126
- name: (env) => env.model.getters.getActiveCols().size > 1 ? _lt("Sort columns") : _lt("Sort column"),
9127
- sequence: 50,
9193
+ execute: PASTE_FORMAT_ACTION,
9194
+ };
9195
+ const findAndReplace = {
9196
+ name: _lt("Find and replace"),
9197
+ description: "Ctrl+H",
9198
+ isReadonlyAllowed: true,
9199
+ execute: OPEN_FAR_SIDEPANEL_ACTION,
9200
+ };
9201
+ const deleteValues = {
9202
+ name: _lt("Delete values"),
9203
+ execute: DELETE_CONTENT_ACTION,
9204
+ };
9205
+ const deleteRows = {
9206
+ name: REMOVE_ROWS_NAME,
9207
+ execute: REMOVE_ROWS_ACTION,
9208
+ };
9209
+ const deleteRow = {
9210
+ ...deleteRows,
9128
9211
  isVisible: IS_ONLY_ONE_RANGE,
9129
- separator: true,
9130
- })
9131
- .addChild("sort_ascending", ["sort_columns"], {
9132
- name: _lt("Ascending (A ⟶ Z)"),
9133
- sequence: 10,
9134
- action: SORT_CELLS_ASCENDING,
9135
- })
9136
- .addChild("sort_descending", ["sort_columns"], {
9137
- name: _lt("Descending (Z ⟶ A)"),
9138
- sequence: 20,
9139
- action: SORT_CELLS_DESCENDING,
9140
- })
9141
- .add("add_column_before", {
9142
- name: COLUMN_INSERT_COLUMNS_BEFORE_NAME,
9143
- sequence: 70,
9144
- action: INSERT_COLUMNS_BEFORE_ACTION,
9145
- })
9146
- .add("add_column_after", {
9147
- name: COLUMN_INSERT_COLUMNS_AFTER_NAME,
9148
- sequence: 80,
9149
- action: INSERT_COLUMNS_AFTER_ACTION,
9150
- })
9151
- .add("delete_column", {
9212
+ };
9213
+ const clearRows = {
9214
+ name: DELETE_CONTENT_ROWS_NAME,
9215
+ execute: DELETE_CONTENT_ROWS_ACTION,
9216
+ };
9217
+ const deleteCols = {
9152
9218
  name: REMOVE_COLUMNS_NAME,
9153
- sequence: 90,
9154
- action: REMOVE_COLUMNS_ACTION,
9155
- })
9156
- .add("clear_column", {
9219
+ execute: REMOVE_COLUMNS_ACTION,
9220
+ };
9221
+ const deleteCol = {
9222
+ ...deleteCols,
9223
+ isVisible: IS_ONLY_ONE_RANGE,
9224
+ };
9225
+ const clearCols = {
9157
9226
  name: DELETE_CONTENT_COLUMNS_NAME,
9158
- sequence: 100,
9159
- action: DELETE_CONTENT_COLUMNS_ACTION,
9160
- })
9161
- .add("hide_columns", {
9162
- name: HIDE_COLUMNS_NAME,
9163
- sequence: 85,
9164
- action: HIDE_COLUMNS_ACTION,
9165
- isVisible: (env) => {
9166
- const sheetId = env.model.getters.getActiveSheetId();
9167
- const hiddenCols = env.model.getters.getHiddenColsGroups(sheetId).flat();
9168
- return (env.model.getters.getNumberCols(sheetId) >
9169
- hiddenCols.length + env.model.getters.getElementsFromSelection("COL").length);
9170
- },
9171
- separator: true,
9172
- })
9173
- .add("unhide_columns", {
9174
- name: _lt("Unhide columns"),
9175
- sequence: 86,
9176
- action: UNHIDE_COLUMNS_ACTION,
9177
- isVisible: (env) => {
9178
- const hiddenCols = env.model.getters
9179
- .getHiddenColsGroups(env.model.getters.getActiveSheetId())
9180
- .flat();
9181
- const currentCols = env.model.getters.getElementsFromSelection("COL");
9182
- return currentCols.some((col) => hiddenCols.includes(col));
9183
- },
9184
- separator: true,
9185
- })
9186
- .add("conditional_formatting", {
9187
- name: _lt("Conditional formatting"),
9188
- sequence: 110,
9189
- action: OPEN_CF_SIDEPANEL_ACTION,
9190
- });
9227
+ execute: DELETE_CONTENT_COLUMNS_ACTION,
9228
+ };
9229
+ const deleteCells = {
9230
+ name: _lt("Delete cells"),
9231
+ isVisible: IS_ONLY_ONE_RANGE,
9232
+ };
9233
+ const deleteCellShiftUp = {
9234
+ name: _lt("Delete cell and shift up"),
9235
+ execute: DELETE_CELL_SHIFT_UP,
9236
+ };
9237
+ const deleteCellShiftLeft = {
9238
+ name: _lt("Delete cell and shift left"),
9239
+ execute: DELETE_CELL_SHIFT_LEFT,
9240
+ };
9241
+ const mergeCells = {
9242
+ name: _lt("Merge cells"),
9243
+ isEnabled: (env) => !cannotMerge(env),
9244
+ isActive: (env) => isInMerge(env),
9245
+ execute: (env) => toggleMerge(env),
9246
+ icon: "o-spreadsheet-Icon.MERGE_CELL",
9247
+ };
9248
+ function cannotMerge(env) {
9249
+ const zones = env.model.getters.getSelectedZones();
9250
+ const { top, left, right, bottom } = env.model.getters.getSelectedZone();
9251
+ const { sheetId } = env.model.getters.getActivePosition();
9252
+ const { xSplit, ySplit } = env.model.getters.getPaneDivisions(sheetId);
9253
+ return (zones.length > 1 ||
9254
+ (top === bottom && left === right) ||
9255
+ (left < xSplit && xSplit <= right) ||
9256
+ (top < ySplit && ySplit <= bottom));
9257
+ }
9258
+ function isInMerge(env) {
9259
+ if (!cannotMerge(env)) {
9260
+ const zones = env.model.getters.getSelectedZones();
9261
+ const { col, row, sheetId } = env.model.getters.getActivePosition();
9262
+ const zone = env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
9263
+ return isEqual(zones[0], zone);
9264
+ }
9265
+ return false;
9266
+ }
9267
+ function toggleMerge(env) {
9268
+ if (cannotMerge(env)) {
9269
+ return;
9270
+ }
9271
+ const zones = env.model.getters.getSelectedZones();
9272
+ const target = [zones[zones.length - 1]];
9273
+ const sheetId = env.model.getters.getActiveSheetId();
9274
+ if (isInMerge(env)) {
9275
+ env.model.dispatch("REMOVE_MERGE", { sheetId, target });
9276
+ }
9277
+ else {
9278
+ interactiveAddMerge(env, sheetId, target);
9279
+ }
9280
+ }
9191
9281
 
9192
- const rowMenuRegistry = new MenuItemRegistry();
9193
- rowMenuRegistry
9194
- .add("cut", {
9195
- name: _lt("Cut"),
9196
- sequence: 10,
9197
- description: "Ctrl+X",
9198
- action: CUT_ACTION,
9199
- })
9200
- .add("copy", {
9201
- name: _lt("Copy"),
9202
- description: "Ctrl+C",
9203
- sequence: 20,
9204
- isReadonlyAllowed: true,
9205
- action: COPY_ACTION,
9206
- })
9207
- .add("paste", {
9208
- name: _lt("Paste"),
9209
- description: "Ctrl+V",
9210
- sequence: 30,
9211
- action: PASTE_ACTION,
9212
- })
9213
- .add("paste_special", {
9214
- name: _lt("Paste special"),
9215
- sequence: 40,
9216
- separator: true,
9217
- isVisible: IS_NOT_CUT_OPERATION,
9218
- })
9219
- .addChild("paste_value_only", ["paste_special"], {
9220
- name: _lt("Paste value only"),
9221
- sequence: 10,
9222
- action: PASTE_VALUE_ACTION,
9223
- })
9224
- .addChild("paste_format_only", ["paste_special"], {
9225
- name: _lt("Paste format only"),
9226
- sequence: 20,
9227
- action: PASTE_FORMAT_ACTION,
9228
- })
9229
- .add("add_row_before", {
9230
- name: ROW_INSERT_ROWS_BEFORE_NAME,
9231
- sequence: 50,
9232
- action: INSERT_ROWS_BEFORE_ACTION,
9233
- })
9234
- .add("add_row_after", {
9235
- name: ROW_INSERT_ROWS_AFTER_NAME,
9236
- sequence: 60,
9237
- action: INSERT_ROWS_AFTER_ACTION,
9238
- })
9239
- .add("delete_row", {
9240
- name: REMOVE_ROWS_NAME,
9241
- sequence: 70,
9242
- action: REMOVE_ROWS_ACTION,
9243
- })
9244
- .add("clear_row", {
9245
- name: DELETE_CONTENT_ROWS_NAME,
9246
- sequence: 80,
9247
- action: DELETE_CONTENT_ROWS_ACTION,
9248
- })
9249
- .add("hide_rows", {
9250
- name: HIDE_ROWS_NAME,
9251
- sequence: 85,
9252
- action: HIDE_ROWS_ACTION,
9253
- isVisible: (env) => {
9254
- const sheetId = env.model.getters.getActiveSheetId();
9255
- const hiddenRows = env.model.getters.getHiddenRowsGroups(sheetId).flat();
9256
- return (env.model.getters.getNumberRows(sheetId) >
9257
- hiddenRows.length + env.model.getters.getElementsFromSelection("ROW").length);
9258
- },
9259
- separator: true,
9260
- })
9261
- .add("unhide_rows", {
9262
- name: _lt("Unhide rows"),
9263
- sequence: 86,
9264
- action: UNHIDE_ROWS_ACTION,
9265
- isVisible: (env) => {
9266
- const hiddenRows = env.model.getters
9267
- .getHiddenRowsGroups(env.model.getters.getActiveSheetId())
9268
- .flat();
9269
- const currentRows = env.model.getters.getElementsFromSelection("ROW");
9270
- return currentRows.some((col) => hiddenRows.includes(col));
9271
- },
9272
- separator: true,
9273
- })
9274
- .add("conditional_formatting", {
9275
- name: _lt("Conditional formatting"),
9276
- sequence: 90,
9277
- action: OPEN_CF_SIDEPANEL_ACTION,
9282
+ var ACTION_EDIT = /*#__PURE__*/Object.freeze({
9283
+ __proto__: null,
9284
+ undo: undo,
9285
+ redo: redo,
9286
+ copy: copy,
9287
+ cut: cut,
9288
+ paste: paste,
9289
+ pasteSpecial: pasteSpecial,
9290
+ pasteSpecialValue: pasteSpecialValue,
9291
+ pasteSpecialFormat: pasteSpecialFormat,
9292
+ findAndReplace: findAndReplace,
9293
+ deleteValues: deleteValues,
9294
+ deleteRows: deleteRows,
9295
+ deleteRow: deleteRow,
9296
+ clearRows: clearRows,
9297
+ deleteCols: deleteCols,
9298
+ deleteCol: deleteCol,
9299
+ clearCols: clearCols,
9300
+ deleteCells: deleteCells,
9301
+ deleteCellShiftUp: deleteCellShiftUp,
9302
+ deleteCellShiftLeft: deleteCellShiftLeft,
9303
+ mergeCells: mergeCells
9278
9304
  });
9279
9305
 
9280
- function getSheetMenuRegistry(args) {
9281
- const sheetMenuRegistry = new MenuItemRegistry();
9282
- sheetMenuRegistry
9283
- .add("delete", {
9284
- name: _lt("Delete"),
9285
- sequence: 10,
9286
- isVisible: (env) => {
9287
- return env.model.getters.getSheetIds().length > 1;
9288
- },
9289
- action: (env) => env.askConfirmation(_lt("Are you sure you want to delete this sheet ?"), () => {
9290
- env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
9291
- }),
9292
- })
9293
- .add("duplicate", {
9294
- name: _lt("Duplicate"),
9295
- sequence: 20,
9296
- action: (env) => {
9297
- const sheetIdFrom = env.model.getters.getActiveSheetId();
9298
- const sheetIdTo = env.model.uuidGenerator.uuidv4();
9299
- env.model.dispatch("DUPLICATE_SHEET", {
9300
- sheetId: sheetIdFrom,
9301
- sheetIdTo,
9302
- });
9303
- env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
9304
- },
9305
- })
9306
- .add("rename", {
9307
- name: _lt("Rename"),
9308
- sequence: 30,
9309
- action: () => args.renameSheetCallback(),
9310
- })
9311
- .add("move_right", {
9312
- name: _lt("Move right"),
9313
- sequence: 40,
9314
- isVisible: (env) => {
9315
- const sheetId = env.model.getters.getActiveSheetId();
9316
- const sheetIds = env.model.getters.getVisibleSheetIds();
9317
- return sheetIds.indexOf(sheetId) !== sheetIds.length - 1;
9318
- },
9319
- action: (env) => env.model.dispatch("MOVE_SHEET", {
9320
- sheetId: env.model.getters.getActiveSheetId(),
9321
- delta: 1,
9322
- }),
9323
- })
9324
- .add("move_left", {
9325
- name: _lt("Move left"),
9326
- sequence: 50,
9327
- isVisible: (env) => {
9328
- const sheetId = env.model.getters.getActiveSheetId();
9329
- return env.model.getters.getVisibleSheetIds()[0] !== sheetId;
9330
- },
9331
- action: (env) => env.model.dispatch("MOVE_SHEET", {
9332
- sheetId: env.model.getters.getActiveSheetId(),
9333
- delta: -1,
9334
- }),
9335
- })
9336
- .add("hide_sheet", {
9337
- name: _lt("Hide sheet"),
9338
- sequence: 60,
9339
- isVisible: (env) => env.model.getters.getVisibleSheetIds().length !== 1,
9340
- action: (env) => env.model.dispatch("HIDE_SHEET", { sheetId: env.model.getters.getActiveSheetId() }),
9341
- });
9342
- return sheetMenuRegistry;
9343
- }
9344
-
9345
9306
  //------------------------------------------------------------------------------
9346
9307
  // Arg description DSL
9347
9308
  //------------------------------------------------------------------------------
@@ -15105,7 +15066,7 @@ const ADDRESS = {
15105
15066
  cellReference = rowPart + colPart;
15106
15067
  }
15107
15068
  if (sheet !== undefined) {
15108
- return `${getComposerSheetName(toString(sheet))}!${cellReference}`;
15069
+ return `${getCanonicalSheetName(toString(sheet))}!${cellReference}`;
15109
15070
  }
15110
15071
  return cellReference;
15111
15072
  },
@@ -16102,6 +16063,593 @@ for (let category of categories) {
16102
16063
  }
16103
16064
  }
16104
16065
 
16066
+ const rowInsertRowBefore = {
16067
+ name: ROW_INSERT_ROWS_BEFORE_NAME,
16068
+ execute: INSERT_ROWS_BEFORE_ACTION,
16069
+ };
16070
+ const topBarInsertRowsBefore = {
16071
+ ...rowInsertRowBefore,
16072
+ name: MENU_INSERT_ROWS_BEFORE_NAME,
16073
+ isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16074
+ };
16075
+ const cellInsertRowsBefore = {
16076
+ ...rowInsertRowBefore,
16077
+ name: CELL_INSERT_ROWS_BEFORE_NAME,
16078
+ isVisible: IS_ONLY_ONE_RANGE,
16079
+ };
16080
+ const rowInsertRowsAfter = {
16081
+ execute: INSERT_ROWS_AFTER_ACTION,
16082
+ name: ROW_INSERT_ROWS_AFTER_NAME,
16083
+ };
16084
+ const topBarInsertRowsAfter = {
16085
+ ...rowInsertRowsAfter,
16086
+ name: MENU_INSERT_ROWS_AFTER_NAME,
16087
+ isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16088
+ };
16089
+ const colInsertColsBefore = {
16090
+ name: COLUMN_INSERT_COLUMNS_BEFORE_NAME,
16091
+ execute: INSERT_COLUMNS_BEFORE_ACTION,
16092
+ };
16093
+ const topBarInsertColsBefore = {
16094
+ ...colInsertColsBefore,
16095
+ name: MENU_INSERT_COLUMNS_BEFORE_NAME,
16096
+ isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16097
+ };
16098
+ const cellInsertColsBefore = {
16099
+ ...colInsertColsBefore,
16100
+ name: CELL_INSERT_COLUMNS_BEFORE_NAME,
16101
+ isVisible: IS_ONLY_ONE_RANGE,
16102
+ };
16103
+ const colInsertColsAfter = {
16104
+ name: COLUMN_INSERT_COLUMNS_AFTER_NAME,
16105
+ execute: INSERT_COLUMNS_AFTER_ACTION,
16106
+ };
16107
+ const topBarInsertColsAfter = {
16108
+ ...colInsertColsAfter,
16109
+ name: MENU_INSERT_COLUMNS_AFTER_NAME,
16110
+ execute: INSERT_COLUMNS_AFTER_ACTION,
16111
+ isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16112
+ };
16113
+ const insertCell = {
16114
+ name: _lt("Insert cells"),
16115
+ isVisible: IS_ONLY_ONE_RANGE,
16116
+ };
16117
+ const insertCellShiftDown = {
16118
+ name: _lt("Insert cells and shift down"),
16119
+ execute: INSERT_CELL_SHIFT_DOWN,
16120
+ };
16121
+ const insertCellShiftRight = {
16122
+ name: _lt("Insert cells and shift right"),
16123
+ execute: INSERT_CELL_SHIFT_RIGHT,
16124
+ };
16125
+ const insertChart = {
16126
+ name: _lt("Chart"),
16127
+ execute: CREATE_CHART,
16128
+ };
16129
+ const insertImage = {
16130
+ name: _lt("Image"),
16131
+ execute: CREATE_IMAGE,
16132
+ isVisible: (env) => env.imageProvider !== undefined,
16133
+ };
16134
+ const insertFunction = {
16135
+ name: _lt("Function"),
16136
+ };
16137
+ const insertFunctionSum = {
16138
+ name: _lt("SUM"),
16139
+ execute: (env) => env.startCellEdition(`=SUM(`),
16140
+ };
16141
+ const insertFunctionAverage = {
16142
+ name: _lt("AVERAGE"),
16143
+ execute: (env) => env.startCellEdition(`=AVERAGE(`),
16144
+ };
16145
+ const insertFunctionCount = {
16146
+ name: _lt("COUNT"),
16147
+ execute: (env) => env.startCellEdition(`=COUNT(`),
16148
+ };
16149
+ const insertFunctionMax = {
16150
+ name: _lt("MAX"),
16151
+ execute: (env) => env.startCellEdition(`=MAX(`),
16152
+ };
16153
+ const insertFunctionMin = {
16154
+ name: _lt("MIN"),
16155
+ execute: (env) => env.startCellEdition(`=MIN(`),
16156
+ };
16157
+ const categorieFunctionAll = {
16158
+ name: _lt("All"),
16159
+ children: allFunctionListMenuBuilder(),
16160
+ };
16161
+ function allFunctionListMenuBuilder() {
16162
+ const fnNames = functionRegistry.getKeys();
16163
+ return createFormulaFunctions(fnNames);
16164
+ }
16165
+ const categoriesFunctionListMenuBuilder = () => {
16166
+ const functions = functionRegistry.content;
16167
+ const categories = [...new Set(functionRegistry.getAll().map((fn) => fn.category))].filter(isDefined$1);
16168
+ return categories.sort().map((category, i) => {
16169
+ const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
16170
+ return {
16171
+ name: category,
16172
+ children: createFormulaFunctions(functionsInCategory),
16173
+ };
16174
+ });
16175
+ };
16176
+ const insertLink = {
16177
+ name: _lt("Link"),
16178
+ execute: INSERT_LINK,
16179
+ };
16180
+ const insertSheet = {
16181
+ name: _lt("New sheet"),
16182
+ execute: CREATE_SHEET_ACTION,
16183
+ };
16184
+ function createFormulaFunctions(fnNames) {
16185
+ return fnNames.sort().map((fnName, i) => {
16186
+ return {
16187
+ name: fnName,
16188
+ sequence: i * 10,
16189
+ execute: (env) => env.startCellEdition(`=${fnName}(`),
16190
+ };
16191
+ });
16192
+ }
16193
+
16194
+ //------------------------------------------------------------------------------
16195
+ // Context Menu Registry
16196
+ //------------------------------------------------------------------------------
16197
+ const cellMenuRegistry = new MenuItemRegistry();
16198
+ cellMenuRegistry
16199
+ .add("cut", {
16200
+ ...cut,
16201
+ sequence: 10,
16202
+ })
16203
+ .add("copy", {
16204
+ ...copy,
16205
+ sequence: 20,
16206
+ })
16207
+ .add("paste", {
16208
+ ...paste,
16209
+ sequence: 30,
16210
+ })
16211
+ .add("paste_special", {
16212
+ ...pasteSpecial,
16213
+ sequence: 40,
16214
+ separator: true,
16215
+ })
16216
+ .addChild("paste_value_only", ["paste_special"], {
16217
+ ...pasteSpecialValue,
16218
+ sequence: 10,
16219
+ })
16220
+ .addChild("paste_format_only", ["paste_special"], {
16221
+ ...pasteSpecialFormat,
16222
+ sequence: 20,
16223
+ })
16224
+ .add("add_row_before", {
16225
+ ...cellInsertRowsBefore,
16226
+ sequence: 70,
16227
+ })
16228
+ .add("add_column_before", {
16229
+ ...cellInsertColsBefore,
16230
+ sequence: 90,
16231
+ })
16232
+ .add("insert_cell", {
16233
+ ...insertCell,
16234
+ sequence: 100,
16235
+ separator: true,
16236
+ })
16237
+ .addChild("insert_cell_down", ["insert_cell"], {
16238
+ ...insertCellShiftDown,
16239
+ name: _lt("Shift down"),
16240
+ sequence: 10,
16241
+ })
16242
+ .addChild("insert_cell_right", ["insert_cell"], {
16243
+ ...insertCellShiftRight,
16244
+ name: _lt("Shift right"),
16245
+ sequence: 20,
16246
+ })
16247
+ .add("delete_row", {
16248
+ ...deleteRow,
16249
+ sequence: 110,
16250
+ })
16251
+ .add("delete_column", {
16252
+ ...deleteCol,
16253
+ sequence: 120,
16254
+ })
16255
+ .add("delete_cell", {
16256
+ ...deleteCells,
16257
+ sequence: 130,
16258
+ })
16259
+ .addChild("delete_cell_up", ["delete_cell"], {
16260
+ ...deleteCellShiftUp,
16261
+ name: _lt("Shift up"),
16262
+ sequence: 10,
16263
+ })
16264
+ .addChild("delete_cell_left", ["delete_cell"], {
16265
+ ...deleteCellShiftLeft,
16266
+ name: _lt("Shift left"),
16267
+ sequence: 20,
16268
+ })
16269
+ .add("insert_link", {
16270
+ ...insertLink,
16271
+ name: _lt("Insert link"),
16272
+ sequence: 150,
16273
+ separator: true,
16274
+ });
16275
+
16276
+ const sortRange = {
16277
+ name: _lt("Sort range"),
16278
+ isVisible: IS_ONLY_ONE_RANGE,
16279
+ };
16280
+ const sortAscending = {
16281
+ name: _lt("Ascending (A ⟶ Z)"),
16282
+ execute: SORT_CELLS_ASCENDING,
16283
+ };
16284
+ const sortDescending = {
16285
+ name: _lt("Descending (Z ⟶ A)"),
16286
+ execute: SORT_CELLS_DESCENDING,
16287
+ };
16288
+ const addDataFilter = {
16289
+ name: _lt("Create filter"),
16290
+ execute: FILTERS_CREATE_FILTER_TABLE,
16291
+ isVisible: (env) => !SELECTION_CONTAINS_FILTER(env),
16292
+ isEnabled: (env) => SELECTION_IS_CONTINUOUS(env),
16293
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16294
+ };
16295
+ const removeDataFilter = {
16296
+ name: _lt("Remove filter"),
16297
+ execute: FILTERS_REMOVE_FILTER_TABLE,
16298
+ isVisible: SELECTION_CONTAINS_FILTER,
16299
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16300
+ };
16301
+
16302
+ const formatNumberAutomatic = {
16303
+ name: _lt("Automatic"),
16304
+ execute: FORMAT_AUTOMATIC_ACTION,
16305
+ isActive: (env) => isAutomaticFormatSelected(env),
16306
+ };
16307
+ const formatNumberNumber = {
16308
+ name: _lt("Number"),
16309
+ description: "1,000.12",
16310
+ execute: FORMAT_NUMBER_ACTION,
16311
+ isActive: (env) => isFormatSelected(env, "#,##0.00"),
16312
+ };
16313
+ const formatPercent = {
16314
+ name: _lt("Format as percent"),
16315
+ execute: FORMAT_PERCENT_ACTION,
16316
+ icon: "o-spreadsheet-Icon.PERCENT",
16317
+ };
16318
+ const formatNumberPercent = {
16319
+ name: _lt("Percent"),
16320
+ description: "10.12%",
16321
+ execute: FORMAT_PERCENT_ACTION,
16322
+ isActive: (env) => isFormatSelected(env, "0.00%"),
16323
+ };
16324
+ const formatNumberCurrency = {
16325
+ name: _lt("Currency"),
16326
+ description: "$1,000.12",
16327
+ execute: FORMAT_CURRENCY_ACTION,
16328
+ isActive: (env) => isFormatSelected(env, "[$$]#,##0.00"),
16329
+ };
16330
+ const formatNumberCurrencyRounded = {
16331
+ name: _lt("Currency rounded"),
16332
+ description: "$1,000",
16333
+ execute: FORMAT_CURRENCY_ROUNDED_ACTION,
16334
+ isActive: (env) => isFormatSelected(env, "[$$]#,##0"),
16335
+ };
16336
+ const formatCustomCurrency = {
16337
+ name: _lt("Custom currency"),
16338
+ isVisible: (env) => env.loadCurrencies !== undefined,
16339
+ execute: OPEN_CUSTOM_CURRENCY_SIDEPANEL_ACTION,
16340
+ };
16341
+ const formatNumberDate = {
16342
+ name: _lt("Date"),
16343
+ description: "9/26/2008",
16344
+ execute: FORMAT_DATE_ACTION,
16345
+ isActive: (env) => isFormatSelected(env, "m/d/yyyy"),
16346
+ };
16347
+ const formatNumberTime = {
16348
+ name: _lt("Time"),
16349
+ description: "10:43:00 PM",
16350
+ execute: FORMAT_TIME_ACTION,
16351
+ isActive: (env) => isFormatSelected(env, "hh:mm:ss a"),
16352
+ };
16353
+ const formatNumberDateTime = {
16354
+ name: _lt("Date time"),
16355
+ description: "9/26/2008 22:43:00",
16356
+ execute: FORMAT_DATE_TIME_ACTION,
16357
+ isActive: (env) => isFormatSelected(env, "m/d/yyyy hh:mm:ss"),
16358
+ };
16359
+ const formatNumberDuration = {
16360
+ name: _lt("Duration"),
16361
+ description: "27:51:38",
16362
+ execute: FORMAT_DURATION_ACTION,
16363
+ isActive: (env) => isFormatSelected(env, "hhhh:mm:ss"),
16364
+ };
16365
+ const incraseDecimalPlaces = {
16366
+ name: _lt("Increase decimal places"),
16367
+ icon: "o-spreadsheet-Icon.INCREASE_DECIMAL",
16368
+ execute: (env) => env.model.dispatch("SET_DECIMAL", {
16369
+ sheetId: env.model.getters.getActiveSheetId(),
16370
+ target: env.model.getters.getSelectedZones(),
16371
+ step: 1,
16372
+ }),
16373
+ };
16374
+ const decraseDecimalPlaces = {
16375
+ name: _lt("Decrease decimal places"),
16376
+ icon: "o-spreadsheet-Icon.DECRASE_DECIMAL",
16377
+ execute: (env) => env.model.dispatch("SET_DECIMAL", {
16378
+ sheetId: env.model.getters.getActiveSheetId(),
16379
+ target: env.model.getters.getSelectedZones(),
16380
+ step: -1,
16381
+ }),
16382
+ };
16383
+ const formatBold = {
16384
+ name: _lt("Bold"),
16385
+ description: "Ctrl+B",
16386
+ execute: FORMAT_BOLD_ACTION,
16387
+ icon: "o-spreadsheet-Icon.BOLD",
16388
+ isActive: (env) => !!env.model.getters.getCurrentStyle().bold,
16389
+ };
16390
+ const formatItalic = {
16391
+ name: _lt("Italic"),
16392
+ description: "Ctrl+I",
16393
+ execute: FORMAT_ITALIC_ACTION,
16394
+ icon: "o-spreadsheet-Icon.ITALIC",
16395
+ isActive: (env) => !!env.model.getters.getCurrentStyle().italic,
16396
+ };
16397
+ const formatUnderline = {
16398
+ name: _lt("Underline"),
16399
+ description: "Ctrl+U",
16400
+ execute: FORMAT_UNDERLINE_ACTION,
16401
+ icon: "o-spreadsheet-Icon.UNDERLINE",
16402
+ isActive: (env) => !!env.model.getters.getCurrentStyle().underline,
16403
+ };
16404
+ const formatStrikethrough = {
16405
+ name: _lt("Strikethrough"),
16406
+ execute: FORMAT_STRIKETHROUGH_ACTION,
16407
+ icon: "o-spreadsheet-Icon.STRIKE",
16408
+ isActive: (env) => !!env.model.getters.getCurrentStyle().strikethrough,
16409
+ };
16410
+ const formatFontSize = {
16411
+ name: _lt("Font size"),
16412
+ children: fontSizeMenuBuilder(),
16413
+ };
16414
+ const formatAlignment = {
16415
+ name: _lt("Alignment"),
16416
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16417
+ };
16418
+ const formatAlignmentHorizontal = {
16419
+ name: _lt("Horizontal align"),
16420
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16421
+ };
16422
+ const formatAlignmentLeft = {
16423
+ name: _lt("Left"),
16424
+ execute: (env) => setStyle(env, { align: "left" }),
16425
+ isActive: (env) => getHorizontalAlign(env) === "left",
16426
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16427
+ };
16428
+ const formatAlignmentCenter = {
16429
+ name: _lt("Center"),
16430
+ execute: (env) => setStyle(env, { align: "center" }),
16431
+ isActive: (env) => getHorizontalAlign(env) === "center",
16432
+ icon: "o-spreadsheet-Icon.ALIGN_CENTER",
16433
+ };
16434
+ const formatAlignmentRight = {
16435
+ name: _lt("Right"),
16436
+ execute: (env) => setStyle(env, { align: "right" }),
16437
+ isActive: (env) => getHorizontalAlign(env) === "right",
16438
+ icon: "o-spreadsheet-Icon.ALIGN_RIGHT",
16439
+ };
16440
+ const formatAlignmentVertical = {
16441
+ name: _lt("Vertical align"),
16442
+ icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
16443
+ };
16444
+ const formatAlignmentTop = {
16445
+ name: _lt("Top"),
16446
+ execute: (env) => setStyle(env, { verticalAlign: "top" }),
16447
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "top",
16448
+ icon: "o-spreadsheet-Icon.ALIGN_TOP",
16449
+ };
16450
+ const formatAlignmentMiddle = {
16451
+ name: _lt("Middle"),
16452
+ execute: (env) => setStyle(env, { verticalAlign: "middle" }),
16453
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "middle",
16454
+ icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
16455
+ };
16456
+ const formatAlignmentBottom = {
16457
+ name: _lt("Bottom"),
16458
+ execute: (env) => setStyle(env, { verticalAlign: "bottom" }),
16459
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "bottom",
16460
+ icon: "o-spreadsheet-Icon.ALIGN_BOTTOM",
16461
+ };
16462
+ const formatWrapping = {
16463
+ name: _lt("Wrapping"),
16464
+ icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
16465
+ };
16466
+ const formatWrappingOverflow = {
16467
+ name: _lt("Overflow"),
16468
+ execute: (env) => setStyle(env, { wrapping: "overflow" }),
16469
+ isActive: (env) => (env.model.getters.getCurrentStyle().wrapping || "overflow") === "overflow",
16470
+ icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
16471
+ };
16472
+ const formatWrappingWrap = {
16473
+ name: _lt("Wrap"),
16474
+ execute: (env) => setStyle(env, { wrapping: "wrap" }),
16475
+ isActive: (env) => env.model.getters.getCurrentStyle().wrapping === "wrap",
16476
+ icon: "o-spreadsheet-Icon.WRAPPING_WRAP",
16477
+ };
16478
+ const formatWrappingClip = {
16479
+ name: _lt("Clip"),
16480
+ execute: (env) => setStyle(env, { wrapping: "clip" }),
16481
+ isActive: (env) => env.model.getters.getCurrentStyle().wrapping === "clip",
16482
+ icon: "o-spreadsheet-Icon.WRAPPING_CLIP",
16483
+ };
16484
+ const textColor = {
16485
+ name: _lt("Text Color"),
16486
+ icon: "o-spreadsheet-Icon.TEXT_COLOR",
16487
+ };
16488
+ const fillColor = {
16489
+ name: _lt("Fill Color"),
16490
+ icon: "o-spreadsheet-Icon.FILL_COLOR",
16491
+ };
16492
+ const formatCF = {
16493
+ name: _lt("Conditional formatting"),
16494
+ execute: OPEN_CF_SIDEPANEL_ACTION,
16495
+ };
16496
+ const paintFormat = {
16497
+ name: _lt("Paint Format"),
16498
+ execute: (env) => env.model.dispatch("ACTIVATE_PAINT_FORMAT", {
16499
+ target: env.model.getters.getSelectedZones(),
16500
+ }),
16501
+ icon: "o-spreadsheet-Icon.PAINT_FORMAT",
16502
+ isActive: (env) => env.model.getters.isPaintingFormat(),
16503
+ };
16504
+ const clearFormat = {
16505
+ name: _lt("Clear formatting"),
16506
+ execute: FORMAT_CLEARFORMAT_ACTION,
16507
+ icon: "o-spreadsheet-Icon.CLEAR_FORMAT",
16508
+ };
16509
+ const borders = {
16510
+ name: _lt("Borders"),
16511
+ icon: "o-spreadsheet-Icon.BORDERS",
16512
+ };
16513
+ const bordersAll = {
16514
+ name: _lt("All borders"),
16515
+ execute: (env) => setBorder(env, "all"),
16516
+ icon: "o-spreadsheet-Icon.BORDERS",
16517
+ };
16518
+ const bordersInner = {
16519
+ name: _lt("Inner borders"),
16520
+ execute: (env) => setBorder(env, "hv"),
16521
+ icon: "o-spreadsheet-Icon.BORDER_HV",
16522
+ };
16523
+ const bordersHorizontal = {
16524
+ name: _lt("Horizontal borders"),
16525
+ execute: (env) => setBorder(env, "h"),
16526
+ icon: "o-spreadsheet-Icon.BORDER_H",
16527
+ };
16528
+ const bordersVertical = {
16529
+ name: _lt("Vertical borders"),
16530
+ execute: (env) => setBorder(env, "v"),
16531
+ icon: "o-spreadsheet-Icon.BORDER_V",
16532
+ };
16533
+ const bordersExternal = {
16534
+ name: _lt("External borders"),
16535
+ execute: (env) => setBorder(env, "external"),
16536
+ icon: "o-spreadsheet-Icon.BORDER_EXTERNAL",
16537
+ };
16538
+ const bordersLeft = {
16539
+ name: _lt("Left borders"),
16540
+ execute: (env) => setBorder(env, "left"),
16541
+ icon: "o-spreadsheet-Icon.BORDER_LEFT",
16542
+ };
16543
+ const bordersTop = {
16544
+ name: _lt("Top borders"),
16545
+ execute: (env) => setBorder(env, "top"),
16546
+ icon: "o-spreadsheet-Icon.BORDER_TOP",
16547
+ };
16548
+ const bordersRight = {
16549
+ name: _lt("Right borders"),
16550
+ execute: (env) => setBorder(env, "right"),
16551
+ icon: "o-spreadsheet-Icon.BORDER_RIGHT",
16552
+ };
16553
+ const bordersBottom = {
16554
+ name: _lt("Bottom borders"),
16555
+ execute: (env) => setBorder(env, "bottom"),
16556
+ icon: "o-spreadsheet-Icon.BORDER_BOTTOM",
16557
+ };
16558
+ const bordersClear = {
16559
+ name: _lt("Clear borders"),
16560
+ execute: (env) => setBorder(env, "clear"),
16561
+ icon: "o-spreadsheet-Icon.BORDER_CLEAR",
16562
+ };
16563
+ function fontSizeMenuBuilder() {
16564
+ return FONT_SIZES.map((fs) => {
16565
+ return {
16566
+ name: fs.toString(),
16567
+ sequence: fs,
16568
+ id: `font_size_${fs}`,
16569
+ execute: (env) => setStyle(env, { fontSize: fs }),
16570
+ isActive: (env) => isFontSizeSelected(env, fs),
16571
+ };
16572
+ });
16573
+ }
16574
+ function isAutomaticFormatSelected(env) {
16575
+ const activeCell = env.model.getters.getActiveCell();
16576
+ return !activeCell || !activeCell.format;
16577
+ }
16578
+ function isFormatSelected(env, format) {
16579
+ const activeCell = env.model.getters.getActiveCell();
16580
+ return activeCell && activeCell.format === format;
16581
+ }
16582
+ function isFontSizeSelected(env, fontSize) {
16583
+ const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
16584
+ return currentFontSize === fontSize;
16585
+ }
16586
+ function setBorder(env, command) {
16587
+ env.model.dispatch("SET_FORMATTING", {
16588
+ sheetId: env.model.getters.getActiveSheetId(),
16589
+ target: env.model.getters.getSelectedZones(),
16590
+ border: command,
16591
+ });
16592
+ }
16593
+ function getHorizontalAlign(env) {
16594
+ const style = env.model.getters.getCurrentStyle();
16595
+ if (style.align) {
16596
+ return style.align;
16597
+ }
16598
+ const cell = env.model.getters.getActiveCell();
16599
+ return cell.defaultAlign;
16600
+ }
16601
+
16602
+ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
16603
+ __proto__: null,
16604
+ formatNumberAutomatic: formatNumberAutomatic,
16605
+ formatNumberNumber: formatNumberNumber,
16606
+ formatPercent: formatPercent,
16607
+ formatNumberPercent: formatNumberPercent,
16608
+ formatNumberCurrency: formatNumberCurrency,
16609
+ formatNumberCurrencyRounded: formatNumberCurrencyRounded,
16610
+ formatCustomCurrency: formatCustomCurrency,
16611
+ formatNumberDate: formatNumberDate,
16612
+ formatNumberTime: formatNumberTime,
16613
+ formatNumberDateTime: formatNumberDateTime,
16614
+ formatNumberDuration: formatNumberDuration,
16615
+ incraseDecimalPlaces: incraseDecimalPlaces,
16616
+ decraseDecimalPlaces: decraseDecimalPlaces,
16617
+ formatBold: formatBold,
16618
+ formatItalic: formatItalic,
16619
+ formatUnderline: formatUnderline,
16620
+ formatStrikethrough: formatStrikethrough,
16621
+ formatFontSize: formatFontSize,
16622
+ formatAlignment: formatAlignment,
16623
+ formatAlignmentHorizontal: formatAlignmentHorizontal,
16624
+ formatAlignmentLeft: formatAlignmentLeft,
16625
+ formatAlignmentCenter: formatAlignmentCenter,
16626
+ formatAlignmentRight: formatAlignmentRight,
16627
+ formatAlignmentVertical: formatAlignmentVertical,
16628
+ formatAlignmentTop: formatAlignmentTop,
16629
+ formatAlignmentMiddle: formatAlignmentMiddle,
16630
+ formatAlignmentBottom: formatAlignmentBottom,
16631
+ formatWrapping: formatWrapping,
16632
+ formatWrappingOverflow: formatWrappingOverflow,
16633
+ formatWrappingWrap: formatWrappingWrap,
16634
+ formatWrappingClip: formatWrappingClip,
16635
+ textColor: textColor,
16636
+ fillColor: fillColor,
16637
+ formatCF: formatCF,
16638
+ paintFormat: paintFormat,
16639
+ clearFormat: clearFormat,
16640
+ borders: borders,
16641
+ bordersAll: bordersAll,
16642
+ bordersInner: bordersInner,
16643
+ bordersHorizontal: bordersHorizontal,
16644
+ bordersVertical: bordersVertical,
16645
+ bordersExternal: bordersExternal,
16646
+ bordersLeft: bordersLeft,
16647
+ bordersTop: bordersTop,
16648
+ bordersRight: bordersRight,
16649
+ bordersBottom: bordersBottom,
16650
+ bordersClear: bordersClear
16651
+ });
16652
+
16105
16653
  function interactiveFreezeColumnsRows(env, dimension, base) {
16106
16654
  const sheetId = env.model.getters.getActiveSheetId();
16107
16655
  const cmd = dimension === "COL" ? "FREEZE_COLUMNS" : "FREEZE_ROWS";
@@ -16111,524 +16659,740 @@ function interactiveFreezeColumnsRows(env, dimension, base) {
16111
16659
  }
16112
16660
  }
16113
16661
 
16114
- const topbarMenuRegistry = new MenuItemRegistry();
16115
- topbarMenuRegistry
16116
- .add("file", { name: _lt("File"), sequence: 10 })
16117
- .add("edit", { name: _lt("Edit"), sequence: 20 })
16118
- .add("view", { name: _lt("View"), sequence: 30 })
16119
- .add("insert", { name: _lt("Insert"), sequence: 40 })
16120
- .add("format", { name: _lt("Format"), sequence: 50 })
16121
- .add("data", { name: _lt("Data"), sequence: 60 })
16122
- .addChild("save", ["file"], {
16123
- name: _lt("Save"),
16124
- description: "Ctrl+S",
16125
- sequence: 10,
16126
- action: () => console.log("Not implemented"),
16127
- })
16128
- .addChild("undo", ["edit"], {
16129
- name: _lt("Undo"),
16130
- description: "Ctrl+Z",
16662
+ const hideCols = {
16663
+ name: HIDE_COLUMNS_NAME,
16664
+ execute: HIDE_COLUMNS_ACTION,
16665
+ isVisible: (env) => {
16666
+ const sheetId = env.model.getters.getActiveSheetId();
16667
+ const hiddenCols = env.model.getters.getHiddenColsGroups(sheetId).flat();
16668
+ return (env.model.getters.getNumberCols(sheetId) >
16669
+ hiddenCols.length + env.model.getters.getElementsFromSelection("COL").length);
16670
+ },
16671
+ };
16672
+ const unhideCols = {
16673
+ name: _lt("Unhide columns"),
16674
+ execute: UNHIDE_COLUMNS_ACTION,
16675
+ isVisible: (env) => {
16676
+ const hiddenCols = env.model.getters
16677
+ .getHiddenColsGroups(env.model.getters.getActiveSheetId())
16678
+ .flat();
16679
+ const currentCols = env.model.getters.getElementsFromSelection("COL");
16680
+ return currentCols.some((col) => hiddenCols.includes(col));
16681
+ },
16682
+ };
16683
+ const unhideAllCols = {
16684
+ name: _lt("Unhide all columns"),
16685
+ execute: UNHIDE_ALL_COLUMNS_ACTION,
16686
+ isVisible: (env) => env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId()).length > 0,
16687
+ };
16688
+ const hideRows = {
16689
+ name: HIDE_ROWS_NAME,
16690
+ execute: HIDE_ROWS_ACTION,
16691
+ isVisible: (env) => {
16692
+ const sheetId = env.model.getters.getActiveSheetId();
16693
+ const hiddenRows = env.model.getters.getHiddenRowsGroups(sheetId).flat();
16694
+ return (env.model.getters.getNumberRows(sheetId) >
16695
+ hiddenRows.length + env.model.getters.getElementsFromSelection("ROW").length);
16696
+ },
16697
+ };
16698
+ const unhideRows = {
16699
+ name: _lt("Unhide rows"),
16700
+ execute: UNHIDE_ROWS_ACTION,
16701
+ isVisible: (env) => {
16702
+ const hiddenRows = env.model.getters
16703
+ .getHiddenRowsGroups(env.model.getters.getActiveSheetId())
16704
+ .flat();
16705
+ const currentRows = env.model.getters.getElementsFromSelection("ROW");
16706
+ return currentRows.some((col) => hiddenRows.includes(col));
16707
+ },
16708
+ };
16709
+ const unhideAllRows = {
16710
+ name: _lt("Unhide all rows"),
16711
+ execute: UNHIDE_ALL_ROWS_ACTION,
16712
+ isVisible: (env) => env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId()).length > 0,
16713
+ };
16714
+ const unFreezePane = {
16715
+ name: _lt("Unfreeze"),
16716
+ isVisible: (env) => {
16717
+ const { xSplit, ySplit } = env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId());
16718
+ return xSplit + ySplit > 0;
16719
+ },
16720
+ execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS_ROWS", {
16721
+ sheetId: env.model.getters.getActiveSheetId(),
16722
+ }),
16723
+ };
16724
+ const freezePane = {
16725
+ name: _lt("Freeze"),
16726
+ };
16727
+ const unFreezeRows = {
16728
+ name: _lt("No rows"),
16729
+ execute: (env) => env.model.dispatch("UNFREEZE_ROWS", {
16730
+ sheetId: env.model.getters.getActiveSheetId(),
16731
+ }),
16732
+ isReadonlyAllowed: true,
16733
+ isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).ySplit,
16734
+ };
16735
+ const freezeFirstRow = {
16736
+ name: _lt("1 row"),
16737
+ execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 1),
16738
+ isReadonlyAllowed: true,
16739
+ };
16740
+ const freezeSecondRow = {
16741
+ name: _lt("2 rows"),
16742
+ execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 2),
16743
+ isReadonlyAllowed: true,
16744
+ };
16745
+ const freezeCurrentRow = {
16746
+ name: _lt("Up to current row"),
16747
+ execute: (env) => {
16748
+ const { bottom } = env.model.getters.getSelectedZone();
16749
+ interactiveFreezeColumnsRows(env, "ROW", bottom + 1);
16750
+ },
16751
+ isReadonlyAllowed: true,
16752
+ };
16753
+ const unFreezeCols = {
16754
+ name: _lt("No columns"),
16755
+ execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS", {
16756
+ sheetId: env.model.getters.getActiveSheetId(),
16757
+ }),
16758
+ isReadonlyAllowed: true,
16759
+ isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).xSplit,
16760
+ };
16761
+ const freezeFirstCol = {
16762
+ name: _lt("1 column"),
16763
+ execute: (env) => interactiveFreezeColumnsRows(env, "COL", 1),
16764
+ isReadonlyAllowed: true,
16765
+ };
16766
+ const freezeSecondCol = {
16767
+ name: _lt("2 columns"),
16768
+ execute: (env) => interactiveFreezeColumnsRows(env, "COL", 2),
16769
+ isReadonlyAllowed: true,
16770
+ };
16771
+ const freezeCurrentCol = {
16772
+ name: _lt("Up to current column"),
16773
+ execute: (env) => {
16774
+ const { right } = env.model.getters.getSelectedZone();
16775
+ interactiveFreezeColumnsRows(env, "COL", right + 1);
16776
+ },
16777
+ isReadonlyAllowed: true,
16778
+ };
16779
+ const viewGridlines = {
16780
+ name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
16781
+ ? _lt("Hide gridlines")
16782
+ : _lt("Show gridlines"),
16783
+ execute: SET_GRID_LINES_VISIBILITY_ACTION,
16784
+ };
16785
+ const viewFormulas = {
16786
+ name: (env) => env.model.getters.shouldShowFormulas() ? _lt("Hide formulas") : _lt("Show formulas"),
16787
+ execute: SET_FORMULA_VISIBILITY_ACTION,
16788
+ isReadonlyAllowed: true,
16789
+ };
16790
+ const createRemoveFilter = {
16791
+ name: (env) => selectionContainsFilter(env) ? _lt("Remove selected filters") : _lt("Create filter"),
16792
+ isActive: (env) => selectionContainsFilter(env),
16793
+ isEnabled: (env) => !cannotCreateFilter(env),
16794
+ execute: (env) => createRemoveFilterAction(env),
16795
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16796
+ };
16797
+ function selectionContainsFilter(env) {
16798
+ const sheetId = env.model.getters.getActiveSheetId();
16799
+ const selectedZones = env.model.getters.getSelectedZones();
16800
+ return env.model.getters.doesZonesContainFilter(sheetId, selectedZones);
16801
+ }
16802
+ function cannotCreateFilter(env) {
16803
+ return !areZonesContinuous(...env.model.getters.getSelectedZones());
16804
+ }
16805
+ function createRemoveFilterAction(env) {
16806
+ if (selectionContainsFilter(env)) {
16807
+ env.model.dispatch("REMOVE_FILTER_TABLE", {
16808
+ sheetId: env.model.getters.getActiveSheetId(),
16809
+ target: env.model.getters.getSelectedZones(),
16810
+ });
16811
+ return;
16812
+ }
16813
+ if (cannotCreateFilter(env)) {
16814
+ return;
16815
+ }
16816
+ env.model.selection.selectTableAroundSelection();
16817
+ const sheetId = env.model.getters.getActiveSheetId();
16818
+ const selection = env.model.getters.getSelectedZones();
16819
+ interactiveAddFilter(env, sheetId, selection);
16820
+ }
16821
+
16822
+ var ACTION_VIEW = /*#__PURE__*/Object.freeze({
16823
+ __proto__: null,
16824
+ hideCols: hideCols,
16825
+ unhideCols: unhideCols,
16826
+ unhideAllCols: unhideAllCols,
16827
+ hideRows: hideRows,
16828
+ unhideRows: unhideRows,
16829
+ unhideAllRows: unhideAllRows,
16830
+ unFreezePane: unFreezePane,
16831
+ freezePane: freezePane,
16832
+ unFreezeRows: unFreezeRows,
16833
+ freezeFirstRow: freezeFirstRow,
16834
+ freezeSecondRow: freezeSecondRow,
16835
+ freezeCurrentRow: freezeCurrentRow,
16836
+ unFreezeCols: unFreezeCols,
16837
+ freezeFirstCol: freezeFirstCol,
16838
+ freezeSecondCol: freezeSecondCol,
16839
+ freezeCurrentCol: freezeCurrentCol,
16840
+ viewGridlines: viewGridlines,
16841
+ viewFormulas: viewFormulas,
16842
+ createRemoveFilter: createRemoveFilter
16843
+ });
16844
+
16845
+ const colMenuRegistry = new MenuItemRegistry();
16846
+ colMenuRegistry
16847
+ .add("cut", {
16848
+ ...cut,
16131
16849
  sequence: 10,
16132
- action: UNDO_ACTION,
16133
16850
  })
16134
- .addChild("redo", ["edit"], {
16135
- name: _lt("Redo"),
16136
- description: "Ctrl+Y",
16851
+ .add("copy", {
16852
+ ...copy,
16137
16853
  sequence: 20,
16138
- action: REDO_ACTION,
16139
- separator: true,
16140
16854
  })
16141
- .addChild("copy", ["edit"], {
16142
- name: _lt("Copy"),
16143
- description: "Ctrl+C",
16855
+ .add("paste", {
16856
+ ...paste,
16144
16857
  sequence: 30,
16145
- isReadonlyAllowed: true,
16146
- action: COPY_ACTION,
16147
16858
  })
16148
- .addChild("cut", ["edit"], {
16149
- name: _lt("Cut"),
16150
- description: "Ctrl+X",
16859
+ .add("paste_special", {
16860
+ ...pasteSpecial,
16151
16861
  sequence: 40,
16152
- action: CUT_ACTION,
16862
+ separator: true,
16153
16863
  })
16154
- .addChild("paste", ["edit"], {
16155
- name: _lt("Paste"),
16156
- description: "Ctrl+V",
16157
- sequence: 50,
16158
- action: PASTE_ACTION,
16864
+ .addChild("paste_value_only", ["paste_special"], {
16865
+ ...pasteSpecialValue,
16866
+ sequence: 10,
16159
16867
  })
16160
- .addChild("paste_special", ["edit"], {
16161
- name: _lt("Paste special"),
16162
- sequence: 60,
16868
+ .addChild("paste_format_only", ["paste_special"], {
16869
+ ...pasteSpecialFormat,
16870
+ sequence: 20,
16871
+ })
16872
+ .add("sort_columns", {
16873
+ ...sortRange,
16874
+ name: (env) => env.model.getters.getActiveCols().size > 1 ? _lt("Sort columns") : _lt("Sort column"),
16875
+ sequence: 50,
16163
16876
  separator: true,
16164
- isVisible: IS_NOT_CUT_OPERATION,
16165
16877
  })
16166
- .addChild("paste_special_value", ["edit", "paste_special"], {
16167
- name: _lt("Paste value only"),
16878
+ .addChild("sort_ascending", ["sort_columns"], {
16879
+ ...sortAscending,
16168
16880
  sequence: 10,
16169
- action: PASTE_VALUE_ACTION,
16170
16881
  })
16171
- .addChild("paste_special_format", ["edit", "paste_special"], {
16172
- name: _lt("Paste format only"),
16882
+ .addChild("sort_descending", ["sort_columns"], {
16883
+ ...sortDescending,
16173
16884
  sequence: 20,
16174
- action: PASTE_FORMAT_ACTION,
16175
16885
  })
16176
- .addChild("sort_range", ["data"], {
16177
- name: _lt("Sort range"),
16178
- sequence: 20,
16179
- isVisible: IS_ONLY_ONE_RANGE,
16886
+ .add("add_column_before", {
16887
+ ...colInsertColsBefore,
16888
+ sequence: 70,
16889
+ })
16890
+ .add("add_column_after", {
16891
+ ...colInsertColsAfter,
16892
+ sequence: 80,
16893
+ })
16894
+ .add("delete_column", {
16895
+ ...deleteCols,
16896
+ sequence: 90,
16897
+ })
16898
+ .add("clear_column", {
16899
+ ...clearCols,
16900
+ sequence: 100,
16901
+ })
16902
+ .add("hide_columns", {
16903
+ ...hideCols,
16904
+ sequence: 85,
16180
16905
  separator: true,
16181
16906
  })
16182
- .addChild("sort_ascending", ["data", "sort_range"], {
16183
- name: _lt("Ascending (A ⟶ Z)"),
16907
+ .add("unhide_columns", {
16908
+ ...unhideCols,
16909
+ sequence: 86,
16910
+ separator: true,
16911
+ })
16912
+ .add("conditional_formatting", {
16913
+ ...formatCF,
16914
+ sequence: 110,
16915
+ });
16916
+
16917
+ const numberFormatMenuRegistry = new MenuItemRegistry();
16918
+ numberFormatMenuRegistry
16919
+ .add("format_number_automatic", {
16920
+ ...formatNumberAutomatic,
16184
16921
  sequence: 10,
16185
- action: SORT_CELLS_ASCENDING,
16922
+ separator: true,
16186
16923
  })
16187
- .addChild("sort_descending", ["data", "sort_range"], {
16188
- name: _lt("Descending (Z ⟶ A)"),
16924
+ .add("format_number_number", {
16925
+ ...formatNumberNumber,
16189
16926
  sequence: 20,
16190
- action: SORT_CELLS_DESCENDING,
16191
16927
  })
16192
- .addChild("find_and_replace", ["edit"], {
16193
- name: _lt("Find and replace"),
16194
- description: "Ctrl+H",
16195
- sequence: 65,
16196
- isReadonlyAllowed: true,
16197
- action: OPEN_FAR_SIDEPANEL_ACTION,
16928
+ .add("format_number_percent", {
16929
+ ...formatNumberPercent,
16930
+ sequence: 30,
16198
16931
  separator: true,
16199
16932
  })
16200
- .addChild("edit_delete_cell_values", ["edit"], {
16201
- name: _lt("Delete values"),
16202
- sequence: 70,
16203
- action: DELETE_CONTENT_ACTION,
16933
+ .add("format_number_currency", {
16934
+ ...formatNumberCurrency,
16935
+ sequence: 40,
16204
16936
  })
16205
- .addChild("edit_delete_row", ["edit"], {
16206
- name: REMOVE_ROWS_NAME,
16207
- sequence: 80,
16208
- action: REMOVE_ROWS_ACTION,
16937
+ .add("format_number_currency_rounded", {
16938
+ ...formatNumberCurrencyRounded,
16939
+ sequence: 50,
16209
16940
  })
16210
- .addChild("edit_delete_column", ["edit"], {
16211
- name: REMOVE_COLUMNS_NAME,
16212
- sequence: 90,
16213
- action: REMOVE_COLUMNS_ACTION,
16941
+ .add("format_custom_currency", {
16942
+ ...formatCustomCurrency,
16943
+ sequence: 60,
16944
+ separator: true,
16214
16945
  })
16215
- .addChild("edit_delete_cell_shift_up", ["edit"], {
16216
- name: _lt("Delete cell and shift up"),
16217
- sequence: 93,
16218
- action: DELETE_CELL_SHIFT_UP,
16946
+ .add("format_number_date", {
16947
+ ...formatNumberDate,
16948
+ sequence: 70,
16219
16949
  })
16220
- .addChild("edit_delete_cell_shift_left", ["edit"], {
16221
- name: _lt("Delete cell and shift left"),
16222
- sequence: 97,
16223
- action: DELETE_CELL_SHIFT_LEFT,
16950
+ .add("format_number_time", {
16951
+ ...formatNumberTime,
16952
+ sequence: 80,
16224
16953
  })
16225
- .addChild("edit_unhide_columns", ["edit"], {
16226
- name: _lt("Unhide all columns"),
16227
- sequence: 100,
16228
- action: UNHIDE_ALL_COLUMNS_ACTION,
16229
- isVisible: (env) => env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId()).length > 0,
16954
+ .add("format_number_date_time", {
16955
+ ...formatNumberDateTime,
16956
+ sequence: 90,
16230
16957
  })
16231
- .addChild("edit_unhide_rows", ["edit"], {
16232
- name: _lt("Unhide all rows"),
16958
+ .add("format_number_duration", {
16959
+ ...formatNumberDuration,
16233
16960
  sequence: 100,
16234
- action: UNHIDE_ALL_ROWS_ACTION,
16235
- isVisible: (env) => env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId()).length > 0,
16236
- })
16237
- .addChild("insert_row_before", ["insert"], {
16238
- name: MENU_INSERT_ROWS_BEFORE_NAME,
16961
+ separator: true,
16962
+ });
16963
+ const formatNumberMenuItemSpec = {
16964
+ name: _lt("More formats"),
16965
+ icon: "o-spreadsheet-Icon.NUMBER_FORMATS",
16966
+ children: [() => numberFormatMenuRegistry.getAll()],
16967
+ };
16968
+
16969
+ const rowMenuRegistry = new MenuItemRegistry();
16970
+ rowMenuRegistry
16971
+ .add("cut", {
16972
+ ...cut,
16239
16973
  sequence: 10,
16240
- action: INSERT_ROWS_BEFORE_ACTION,
16241
- isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16242
16974
  })
16243
- .addChild("insert_row_after", ["insert"], {
16244
- name: MENU_INSERT_ROWS_AFTER_NAME,
16975
+ .add("copy", {
16976
+ ...copy,
16245
16977
  sequence: 20,
16246
- action: INSERT_ROWS_AFTER_ACTION,
16247
- isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16248
- separator: true,
16249
16978
  })
16250
- .addChild("insert_column_before", ["insert"], {
16251
- name: MENU_INSERT_COLUMNS_BEFORE_NAME,
16979
+ .add("paste", {
16980
+ ...paste,
16252
16981
  sequence: 30,
16253
- action: INSERT_COLUMNS_BEFORE_ACTION,
16254
- isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16255
16982
  })
16256
- .addChild("insert_column_after", ["insert"], {
16257
- name: MENU_INSERT_COLUMNS_AFTER_NAME,
16983
+ .add("paste_special", {
16984
+ ...pasteSpecial,
16258
16985
  sequence: 40,
16259
- action: INSERT_COLUMNS_AFTER_ACTION,
16260
- isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16261
16986
  separator: true,
16262
16987
  })
16263
- .addChild("insert_insert_cell_shift_down", ["insert"], {
16264
- name: _lt("Insert cells and shift down"),
16265
- sequence: 43,
16266
- action: INSERT_CELL_SHIFT_DOWN,
16988
+ .addChild("paste_value_only", ["paste_special"], {
16989
+ ...pasteSpecialValue,
16990
+ sequence: 10,
16267
16991
  })
16268
- .addChild("insert_insert_cell_shift_right", ["insert"], {
16269
- name: _lt("Insert cells and shift right"),
16270
- sequence: 47,
16271
- action: INSERT_CELL_SHIFT_RIGHT,
16272
- separator: true,
16992
+ .addChild("paste_format_only", ["paste_special"], {
16993
+ ...pasteSpecialFormat,
16994
+ sequence: 20,
16273
16995
  })
16274
- .addChild("insert_chart", ["insert"], {
16275
- name: _lt("Chart"),
16996
+ .add("add_row_before", {
16997
+ ...rowInsertRowBefore,
16276
16998
  sequence: 50,
16277
- action: CREATE_CHART,
16278
- })
16279
- .addChild("insert_image", ["insert"], {
16280
- name: _lt("Image"),
16281
- sequence: 55,
16282
- action: CREATE_IMAGE,
16283
- isVisible: (env) => env.imageProvider !== undefined,
16284
16999
  })
16285
- .addChild("insert_function", ["insert"], {
16286
- name: _lt("Function"),
17000
+ .add("add_row_after", {
17001
+ ...rowInsertRowsAfter,
16287
17002
  sequence: 60,
16288
17003
  })
16289
- .addChild("insert_function_sum", ["insert", "insert_function"], {
16290
- name: _lt("SUM"),
16291
- action: (env) => env.startCellEdition(`=SUM(`),
16292
- sequence: 0,
17004
+ .add("delete_row", {
17005
+ ...deleteRows,
17006
+ sequence: 70,
16293
17007
  })
16294
- .addChild("insert_function_average", ["insert", "insert_function"], {
16295
- name: _lt("AVERAGE"),
16296
- action: (env) => env.startCellEdition(`=AVERAGE(`),
17008
+ .add("clear_row", {
17009
+ ...clearRows,
17010
+ sequence: 80,
17011
+ })
17012
+ .add("hide_rows", {
17013
+ ...hideRows,
17014
+ sequence: 85,
17015
+ separator: true,
17016
+ })
17017
+ .add("unhide_rows", {
17018
+ ...unhideRows,
17019
+ sequence: 86,
17020
+ separator: true,
17021
+ })
17022
+ .add("conditional_formatting", {
17023
+ ...formatCF,
17024
+ sequence: 90,
17025
+ });
17026
+
17027
+ function getSheetMenuRegistry(args) {
17028
+ const sheetMenuRegistry = new MenuItemRegistry();
17029
+ sheetMenuRegistry
17030
+ .add("delete", {
17031
+ ...deleteSheet,
17032
+ sequence: 10,
17033
+ })
17034
+ .add("duplicate", {
17035
+ ...duplicateSheet,
17036
+ sequence: 20,
17037
+ })
17038
+ .add("rename", {
17039
+ ...renameSheet(args),
17040
+ sequence: 30,
17041
+ })
17042
+ .add("move_right", {
17043
+ ...sheetMoveRight,
17044
+ sequence: 40,
17045
+ })
17046
+ .add("move_left", {
17047
+ ...sheetMoveLeft,
17048
+ sequence: 50,
17049
+ })
17050
+ .add("hide_sheet", {
17051
+ ...hideSheet,
17052
+ sequence: 60,
17053
+ });
17054
+ return sheetMenuRegistry;
17055
+ }
17056
+
17057
+ const topbarMenuRegistry = new MenuItemRegistry();
17058
+ topbarMenuRegistry
17059
+ // ---------------------------------------------------------------------
17060
+ // FILE MENU ITEMS
17061
+ // ---------------------------------------------------------------------
17062
+ .add("file", {
17063
+ name: _lt("File"),
16297
17064
  sequence: 10,
16298
17065
  })
16299
- .addChild("insert_function_count", ["insert", "insert_function"], {
16300
- name: _lt("COUNT"),
16301
- action: (env) => env.startCellEdition(`=COUNT(`),
17066
+ // ---------------------------------------------------------------------
17067
+ // EDIT MENU ITEMS
17068
+ // ---------------------------------------------------------------------
17069
+ .add("edit", {
17070
+ name: _lt("Edit"),
16302
17071
  sequence: 20,
16303
17072
  })
16304
- .addChild("insert_function_max", ["insert", "insert_function"], {
16305
- name: _lt("MAX"),
16306
- action: (env) => env.startCellEdition(`=MAX(`),
17073
+ .addChild("undo", ["edit"], {
17074
+ ...undo,
17075
+ sequence: 10,
17076
+ })
17077
+ .addChild("redo", ["edit"], {
17078
+ ...redo,
17079
+ sequence: 20,
17080
+ separator: true,
17081
+ })
17082
+ .addChild("copy", ["edit"], {
17083
+ ...copy,
16307
17084
  sequence: 30,
16308
17085
  })
16309
- .addChild("insert_function_min", ["insert", "insert_function"], {
16310
- name: _lt("MIN"),
16311
- action: (env) => env.startCellEdition(`=MIN(`),
17086
+ .addChild("cut", ["edit"], {
17087
+ ...cut,
16312
17088
  sequence: 40,
16313
- separator: true,
16314
17089
  })
16315
- .addChild("categorie_function_all", ["insert", "insert_function"], {
16316
- name: _lt("All"),
17090
+ .addChild("paste", ["edit"], {
17091
+ ...paste,
16317
17092
  sequence: 50,
16318
17093
  })
16319
- .addChild("all_function_list", ["insert", "insert_function", "categorie_function_all"], () => {
16320
- const fnNames = functionRegistry.getKeys();
16321
- return createFormulaFunctionMenuItems(fnNames);
17094
+ .addChild("paste_special", ["edit"], {
17095
+ ...pasteSpecial,
17096
+ sequence: 60,
17097
+ separator: true,
16322
17098
  })
16323
- .addChild("categories_function_list", ["insert", "insert_function"], () => {
16324
- const functions = functionRegistry.content;
16325
- const categories = [...new Set(functionRegistry.getAll().map((fn) => fn.category))].filter(isDefined$1);
16326
- return categories.sort().map((category, i) => {
16327
- const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
16328
- return {
16329
- name: category,
16330
- sequence: 60 + i * 10,
16331
- children: createFormulaFunctionMenuItems(functionsInCategory),
16332
- };
16333
- });
17099
+ .addChild("paste_special_value", ["edit", "paste_special"], {
17100
+ ...pasteSpecialValue,
17101
+ sequence: 10,
16334
17102
  })
16335
- .addChild("insert_link", ["insert"], {
16336
- name: _lt("Link"),
17103
+ .addChild("paste_special_format", ["edit", "paste_special"], {
17104
+ ...pasteSpecialFormat,
17105
+ sequence: 20,
17106
+ })
17107
+ .addChild("find_and_replace", ["edit"], {
17108
+ ...findAndReplace,
17109
+ sequence: 65,
16337
17110
  separator: true,
17111
+ })
17112
+ .addChild("edit_delete_cell_values", ["edit"], {
17113
+ ...deleteValues,
16338
17114
  sequence: 70,
16339
- action: INSERT_LINK,
16340
17115
  })
16341
- .addChild("insert_sheet", ["insert"], {
16342
- name: _lt("New sheet"),
17116
+ .addChild("edit_delete_row", ["edit"], {
17117
+ ...deleteRows,
16343
17118
  sequence: 80,
16344
- action: CREATE_SHEET_ACTION,
16345
- separator: true,
17119
+ })
17120
+ .addChild("edit_delete_column", ["edit"], {
17121
+ ...deleteCols,
17122
+ sequence: 90,
17123
+ })
17124
+ .addChild("edit_delete_cell_shift_up", ["edit"], {
17125
+ ...deleteCellShiftUp,
17126
+ sequence: 93,
17127
+ })
17128
+ .addChild("edit_delete_cell_shift_left", ["edit"], {
17129
+ ...deleteCellShiftLeft,
17130
+ sequence: 97,
17131
+ })
17132
+ .addChild("edit_unhide_columns", ["edit"], {
17133
+ ...unhideAllCols,
17134
+ sequence: 100,
17135
+ })
17136
+ .addChild("edit_unhide_rows", ["edit"], {
17137
+ ...unhideAllRows,
17138
+ sequence: 100,
17139
+ })
17140
+ // ---------------------------------------------------------------------
17141
+ // VIEW MENU ITEMS
17142
+ // ---------------------------------------------------------------------
17143
+ .add("view", {
17144
+ name: _lt("View"),
17145
+ sequence: 30,
16346
17146
  })
16347
17147
  .addChild("unfreeze_panes", ["view"], {
16348
- name: _lt("Unfreeze"),
17148
+ ...unFreezePane,
16349
17149
  sequence: 4,
16350
- isVisible: (env) => {
16351
- const { xSplit, ySplit } = env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId());
16352
- return xSplit + ySplit > 0;
16353
- },
16354
- action: (env) => env.model.dispatch("UNFREEZE_COLUMNS_ROWS", {
16355
- sheetId: env.model.getters.getActiveSheetId(),
16356
- }),
16357
17150
  })
16358
17151
  .addChild("freeze_panes", ["view"], {
16359
- name: _lt("Freeze"),
17152
+ ...freezePane,
16360
17153
  sequence: 5,
16361
17154
  separator: true,
16362
17155
  })
16363
17156
  .addChild("unfreeze_rows", ["view", "freeze_panes"], {
16364
- name: _lt("No rows"),
16365
- action: (env) => env.model.dispatch("UNFREEZE_ROWS", {
16366
- sheetId: env.model.getters.getActiveSheetId(),
16367
- }),
16368
- isReadonlyAllowed: true,
17157
+ ...unFreezeRows,
16369
17158
  sequence: 5,
16370
- isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).ySplit,
16371
17159
  })
16372
17160
  .addChild("freeze_first_row", ["view", "freeze_panes"], {
16373
- name: _lt("1 row"),
16374
- action: (env) => interactiveFreezeColumnsRows(env, "ROW", 1),
16375
- isReadonlyAllowed: true,
17161
+ ...freezeFirstRow,
16376
17162
  sequence: 10,
16377
17163
  })
16378
17164
  .addChild("freeze_second_row", ["view", "freeze_panes"], {
16379
- name: _lt("2 rows"),
16380
- action: (env) => interactiveFreezeColumnsRows(env, "ROW", 2),
16381
- isReadonlyAllowed: true,
17165
+ ...freezeSecondRow,
16382
17166
  sequence: 15,
16383
17167
  })
16384
17168
  .addChild("freeze_current_row", ["view", "freeze_panes"], {
16385
- name: _lt("Up to current row"),
16386
- action: (env) => {
16387
- const { bottom } = env.model.getters.getSelectedZone();
16388
- interactiveFreezeColumnsRows(env, "ROW", bottom + 1);
16389
- },
16390
- isReadonlyAllowed: true,
17169
+ ...freezeCurrentRow,
16391
17170
  sequence: 20,
16392
17171
  separator: true,
16393
17172
  })
16394
17173
  .addChild("unfreeze_columns", ["view", "freeze_panes"], {
16395
- name: _lt("No columns"),
16396
- action: (env) => env.model.dispatch("UNFREEZE_COLUMNS", {
16397
- sheetId: env.model.getters.getActiveSheetId(),
16398
- }),
16399
- isReadonlyAllowed: true,
17174
+ ...unFreezeCols,
16400
17175
  sequence: 25,
16401
- isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).xSplit,
16402
17176
  })
16403
17177
  .addChild("freeze_first_col", ["view", "freeze_panes"], {
16404
- name: _lt("1 column"),
16405
- action: (env) => interactiveFreezeColumnsRows(env, "COL", 1),
16406
- isReadonlyAllowed: true,
17178
+ ...freezeFirstCol,
16407
17179
  sequence: 30,
16408
17180
  })
16409
17181
  .addChild("freeze_second_col", ["view", "freeze_panes"], {
16410
- name: _lt("2 columns"),
16411
- action: (env) => interactiveFreezeColumnsRows(env, "COL", 2),
16412
- isReadonlyAllowed: true,
17182
+ ...freezeSecondCol,
16413
17183
  sequence: 35,
16414
17184
  })
16415
17185
  .addChild("freeze_current_col", ["view", "freeze_panes"], {
16416
- name: _lt("Up to current column"),
16417
- action: (env) => {
16418
- const { right } = env.model.getters.getSelectedZone();
16419
- interactiveFreezeColumnsRows(env, "COL", right + 1);
16420
- },
16421
- isReadonlyAllowed: true,
17186
+ ...freezeCurrentCol,
16422
17187
  sequence: 40,
16423
17188
  })
16424
17189
  .addChild("view_gridlines", ["view"], {
16425
- name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
16426
- ? _lt("Hide gridlines")
16427
- : _lt("Show gridlines"),
16428
- action: SET_GRID_LINES_VISIBILITY_ACTION,
17190
+ ...viewGridlines,
16429
17191
  sequence: 10,
16430
17192
  })
16431
17193
  .addChild("view_formulas", ["view"], {
16432
- name: (env) => env.model.getters.shouldShowFormulas() ? _lt("Hide formulas") : _lt("Show formulas"),
16433
- action: SET_FORMULA_VISIBILITY_ACTION,
16434
- isReadonlyAllowed: true,
17194
+ ...viewFormulas,
16435
17195
  sequence: 15,
16436
17196
  })
16437
- .addChild("format_number", ["format"], {
16438
- name: _lt("Numbers"),
16439
- sequence: 10,
16440
- separator: true,
17197
+ // ---------------------------------------------------------------------
17198
+ // INSERT MENU ITEMS
17199
+ // ---------------------------------------------------------------------
17200
+ .add("insert", {
17201
+ name: _lt("Insert"),
17202
+ sequence: 40,
16441
17203
  })
16442
- .addChild("format_number_automatic", ["format", "format_number"], {
16443
- name: NumberFormatTerms.Automatic,
17204
+ .addChild("insert_row_before", ["insert"], {
17205
+ ...topBarInsertRowsBefore,
16444
17206
  sequence: 10,
16445
- separator: true,
16446
- action: FORMAT_AUTOMATIC_ACTION,
16447
17207
  })
16448
- .addChild("format_number_number", ["format", "format_number"], {
16449
- name: NumberFormatTerms.Number,
16450
- description: "1,000.12",
17208
+ .addChild("insert_row_after", ["insert"], {
17209
+ ...topBarInsertRowsAfter,
16451
17210
  sequence: 20,
16452
- action: FORMAT_NUMBER_ACTION,
17211
+ separator: true,
16453
17212
  })
16454
- .addChild("format_number_percent", ["format", "format_number"], {
16455
- name: NumberFormatTerms.Percent,
16456
- description: "10.12%",
17213
+ .addChild("insert_column_before", ["insert"], {
17214
+ ...topBarInsertColsBefore,
16457
17215
  sequence: 30,
16458
- separator: true,
16459
- action: FORMAT_PERCENT_ACTION,
16460
17216
  })
16461
- .addChild("format_number_currency", ["format", "format_number"], {
16462
- name: NumberFormatTerms.Currency,
16463
- description: "$1,000.12",
16464
- sequence: 37,
16465
- action: FORMAT_CURRENCY_ACTION,
17217
+ .addChild("insert_column_after", ["insert"], {
17218
+ ...topBarInsertColsAfter,
17219
+ sequence: 40,
17220
+ separator: true,
16466
17221
  })
16467
- .addChild("format_number_currency_rounded", ["format", "format_number"], {
16468
- name: NumberFormatTerms.CurrencyRounded,
16469
- description: "$1,000",
16470
- sequence: 38,
16471
- action: FORMAT_CURRENCY_ROUNDED_ACTION,
17222
+ .addChild("insert_insert_cell_shift_down", ["insert"], {
17223
+ ...insertCellShiftDown,
17224
+ sequence: 43,
16472
17225
  })
16473
- .addChild("format_custom_currency", ["format", "format_number"], {
16474
- name: NumberFormatTerms.CustomCurrency,
16475
- sequence: 39,
17226
+ .addChild("insert_insert_cell_shift_right", ["insert"], {
17227
+ ...insertCellShiftRight,
17228
+ sequence: 47,
16476
17229
  separator: true,
16477
- isVisible: (env) => env.loadCurrencies !== undefined,
16478
- action: OPEN_CUSTOM_CURRENCY_SIDEPANEL_ACTION,
16479
17230
  })
16480
- .addChild("format_number_date", ["format", "format_number"], {
16481
- name: NumberFormatTerms.Date,
16482
- description: "9/26/2008",
16483
- sequence: 40,
16484
- action: FORMAT_DATE_ACTION,
16485
- })
16486
- .addChild("format_number_time", ["format", "format_number"], {
16487
- name: NumberFormatTerms.Time,
16488
- description: "10:43:00 PM",
17231
+ .addChild("insert_chart", ["insert"], {
17232
+ ...insertChart,
16489
17233
  sequence: 50,
16490
- action: FORMAT_TIME_ACTION,
16491
17234
  })
16492
- .addChild("format_number_date_time", ["format", "format_number"], {
16493
- name: NumberFormatTerms.DateTime,
16494
- description: "9/26/2008 22:43:00",
17235
+ .addChild("insert_image", ["insert"], {
17236
+ ...insertImage,
17237
+ sequence: 55,
17238
+ })
17239
+ .addChild("insert_function", ["insert"], {
17240
+ ...insertFunction,
16495
17241
  sequence: 60,
16496
- action: FORMAT_DATE_TIME_ACTION,
16497
17242
  })
16498
- .addChild("format_number_duration", ["format", "format_number"], {
16499
- name: NumberFormatTerms.Duration,
16500
- description: "27:51:38",
17243
+ .addChild("insert_function_sum", ["insert", "insert_function"], {
17244
+ ...insertFunctionSum,
17245
+ sequence: 0,
17246
+ })
17247
+ .addChild("insert_function_average", ["insert", "insert_function"], {
17248
+ ...insertFunctionAverage,
17249
+ sequence: 10,
17250
+ })
17251
+ .addChild("insert_function_count", ["insert", "insert_function"], {
17252
+ ...insertFunctionCount,
17253
+ sequence: 20,
17254
+ })
17255
+ .addChild("insert_function_max", ["insert", "insert_function"], {
17256
+ ...insertFunctionMax,
17257
+ sequence: 30,
17258
+ })
17259
+ .addChild("insert_function_min", ["insert", "insert_function"], {
17260
+ ...insertFunctionMin,
17261
+ sequence: 40,
17262
+ separator: true,
17263
+ })
17264
+ .addChild("categorie_function_all", ["insert", "insert_function"], {
17265
+ ...categorieFunctionAll,
17266
+ sequence: 50,
17267
+ })
17268
+ .addChild("categories_function_list", ["insert", "insert_function"], categoriesFunctionListMenuBuilder)
17269
+ .addChild("insert_link", ["insert"], {
17270
+ ...insertLink,
17271
+ separator: true,
16501
17272
  sequence: 70,
17273
+ })
17274
+ .addChild("insert_sheet", ["insert"], {
17275
+ ...insertSheet,
17276
+ sequence: 80,
17277
+ separator: true,
17278
+ })
17279
+ // ---------------------------------------------------------------------
17280
+ // FORMAT MENU ITEMS
17281
+ // ---------------------------------------------------------------------
17282
+ .add("format", { name: _lt("Format"), sequence: 50 })
17283
+ .addChild("format_number", ["format"], {
17284
+ ...formatNumberMenuItemSpec,
17285
+ name: _lt("Number"),
17286
+ sequence: 10,
16502
17287
  separator: true,
16503
- action: FORMAT_DURATION_ACTION,
16504
17288
  })
16505
17289
  .addChild("format_bold", ["format"], {
16506
- name: _lt("Bold"),
17290
+ ...formatBold,
16507
17291
  sequence: 20,
16508
- description: "Ctrl+B",
16509
- action: FORMAT_BOLD_ACTION,
16510
17292
  })
16511
17293
  .addChild("format_italic", ["format"], {
16512
- name: _lt("Italic"),
17294
+ ...formatItalic,
16513
17295
  sequence: 30,
16514
- description: "Ctrl+I",
16515
- action: FORMAT_ITALIC_ACTION,
16516
17296
  })
16517
17297
  .addChild("format_underline", ["format"], {
16518
- name: _lt("Underline"),
16519
- description: "Ctrl+U",
17298
+ ...formatUnderline,
16520
17299
  sequence: 40,
16521
- action: FORMAT_UNDERLINE_ACTION,
16522
17300
  })
16523
17301
  .addChild("format_strikethrough", ["format"], {
16524
- name: _lt("Strikethrough"),
17302
+ ...formatStrikethrough,
16525
17303
  sequence: 50,
16526
- action: FORMAT_STRIKETHROUGH_ACTION,
16527
17304
  separator: true,
16528
17305
  })
16529
17306
  .addChild("format_font_size", ["format"], {
16530
- name: _lt("Font size"),
17307
+ ...formatFontSize,
16531
17308
  sequence: 60,
16532
17309
  separator: true,
16533
17310
  })
16534
17311
  .addChild("format_alignment", ["format"], {
16535
- name: _lt("Alignment"),
17312
+ ...formatAlignment,
16536
17313
  sequence: 70,
16537
17314
  })
16538
17315
  .addChild("format_alignment_left", ["format", "format_alignment"], {
16539
- name: "Left",
17316
+ ...formatAlignmentLeft,
16540
17317
  sequence: 10,
16541
- action: (env) => setStyle(env, { align: "left" }),
16542
17318
  })
16543
17319
  .addChild("format_alignment_center", ["format", "format_alignment"], {
16544
- name: "Center",
17320
+ ...formatAlignmentCenter,
16545
17321
  sequence: 20,
16546
- action: (env) => setStyle(env, { align: "center" }),
16547
17322
  })
16548
17323
  .addChild("format_alignment_right", ["format", "format_alignment"], {
16549
- name: "Right",
17324
+ ...formatAlignmentRight,
16550
17325
  sequence: 30,
16551
- action: (env) => setStyle(env, { align: "right" }),
16552
17326
  separator: true,
16553
17327
  })
16554
17328
  .addChild("format_alignment_top", ["format", "format_alignment"], {
16555
- name: "Top",
17329
+ ...formatAlignmentTop,
16556
17330
  sequence: 40,
16557
- action: (env) => setStyle(env, { verticalAlign: "top" }),
16558
17331
  })
16559
17332
  .addChild("format_alignment_middle", ["format", "format_alignment"], {
16560
- name: "Middle",
17333
+ ...formatAlignmentMiddle,
16561
17334
  sequence: 50,
16562
- action: (env) => setStyle(env, { verticalAlign: "middle" }),
16563
17335
  })
16564
17336
  .addChild("format_alignment_bottom", ["format", "format_alignment"], {
16565
- name: "Bottom",
17337
+ ...formatAlignmentBottom,
16566
17338
  sequence: 60,
16567
- action: (env) => setStyle(env, { verticalAlign: "bottom" }),
16568
17339
  separator: true,
16569
17340
  })
16570
17341
  .addChild("format_wrapping", ["format"], {
16571
- name: _lt("Wrapping"),
17342
+ ...formatWrapping,
16572
17343
  sequence: 80,
16573
17344
  separator: true,
16574
17345
  })
16575
17346
  .addChild("format_wrapping_overflow", ["format", "format_wrapping"], {
16576
- name: _lt("Overflow"),
17347
+ ...formatWrappingOverflow,
16577
17348
  sequence: 10,
16578
- action: (env) => setStyle(env, { wrapping: "overflow" }),
16579
17349
  })
16580
17350
  .addChild("format_wrapping_wrap", ["format", "format_wrapping"], {
16581
- name: _lt("Wrap"),
17351
+ ...formatWrappingWrap,
16582
17352
  sequence: 20,
16583
- action: (env) => setStyle(env, { wrapping: "wrap" }),
16584
17353
  })
16585
17354
  .addChild("format_wrapping_clip", ["format", "format_wrapping"], {
16586
- name: _lt("Clip"),
17355
+ ...formatWrappingClip,
16587
17356
  sequence: 30,
16588
- action: (env) => setStyle(env, { wrapping: "clip" }),
16589
17357
  })
16590
17358
  .addChild("format_cf", ["format"], {
16591
- name: _lt("Conditional formatting"),
17359
+ ...formatCF,
16592
17360
  sequence: 90,
16593
- action: OPEN_CF_SIDEPANEL_ACTION,
16594
17361
  separator: true,
16595
17362
  })
16596
17363
  .addChild("format_clearFormat", ["format"], {
16597
- name: _lt("Clear formatting"),
17364
+ ...clearFormat,
16598
17365
  sequence: 100,
16599
- action: FORMAT_CLEARFORMAT_ACTION,
16600
17366
  separator: true,
17367
+ })
17368
+ // ---------------------------------------------------------------------
17369
+ // DATA MENU ITEMS
17370
+ // ---------------------------------------------------------------------
17371
+ .add("data", {
17372
+ name: _lt("Data"),
17373
+ sequence: 60,
17374
+ })
17375
+ .addChild("sort_range", ["data"], {
17376
+ ...sortRange,
17377
+ sequence: 20,
17378
+ separator: true,
17379
+ })
17380
+ .addChild("sort_ascending", ["data", "sort_range"], {
17381
+ ...sortAscending,
17382
+ sequence: 10,
17383
+ })
17384
+ .addChild("sort_descending", ["data", "sort_range"], {
17385
+ ...sortDescending,
17386
+ sequence: 20,
16601
17387
  })
16602
17388
  .addChild("add_data_filter", ["data"], {
16603
- name: _lt("Create filter"),
17389
+ ...addDataFilter,
16604
17390
  sequence: 10,
16605
- action: FILTERS_CREATE_FILTER_TABLE,
16606
- isVisible: (env) => !SELECTION_CONTAINS_FILTER(env),
16607
- isEnabled: (env) => SELECTION_IS_CONTINUOUS(env),
16608
17391
  })
16609
17392
  .addChild("remove_data_filter", ["data"], {
16610
- name: _lt("Remove filter"),
17393
+ ...removeDataFilter,
16611
17394
  sequence: 10,
16612
- action: FILTERS_REMOVE_FILTER_TABLE,
16613
- isVisible: SELECTION_CONTAINS_FILTER,
16614
- });
16615
- // Font-sizes
16616
- for (let fs of FONT_SIZES) {
16617
- topbarMenuRegistry.addChild(`format_font_size_${fs}`, ["format", "format_font_size"], {
16618
- name: fs.toString(),
16619
- sequence: fs,
16620
- action: (env) => setStyle(env, { fontSize: fs }),
16621
- });
16622
- }
16623
- function createFormulaFunctionMenuItems(fnNames) {
16624
- return fnNames.sort().map((fnName, i) => {
16625
- return {
16626
- name: fnName,
16627
- sequence: i * 10,
16628
- action: (env) => env.startCellEdition(`=${fnName}(`),
16629
- };
16630
- });
16631
- }
17395
+ });
16632
17396
 
16633
17397
  class OTRegistry extends Registry {
16634
17398
  /**
@@ -16930,6 +17694,22 @@ class LineBarPieConfigPanel extends Component {
16930
17694
  aggregated: ev.target.checked,
16931
17695
  });
16932
17696
  }
17697
+ calculateHeaderPosition() {
17698
+ if (this.isDatasetInvalid || this.isLabelInvalid) {
17699
+ return undefined;
17700
+ }
17701
+ const getters = this.env.model.getters;
17702
+ const sheetId = getters.getActiveSheetId();
17703
+ const labelRange = createRange(getters, sheetId, this.labelRange);
17704
+ const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
17705
+ if (dataSets.length) {
17706
+ return dataSets[0].dataRange.zone.top + 1;
17707
+ }
17708
+ else if (labelRange) {
17709
+ return labelRange.zone.top + 1;
17710
+ }
17711
+ return undefined;
17712
+ }
16933
17713
  }
16934
17714
  LineBarPieConfigPanel.template = "o-spreadsheet-LineBarPieConfigPanel";
16935
17715
  LineBarPieConfigPanel.components = { SelectionInput };
@@ -17177,6 +17957,9 @@ class ColorPicker extends Component {
17177
17957
  top,
17178
17958
  });
17179
17959
  }
17960
+ isSameColor(color1, color2) {
17961
+ return isSameColor(color1, color2);
17962
+ }
17180
17963
  }
17181
17964
  ColorPicker.template = "o-spreadsheet-ColorPicker";
17182
17965
  ColorPicker.defaultProps = {
@@ -17192,8 +17975,9 @@ ColorPicker.props = {
17192
17975
 
17193
17976
  css /* scss */ `
17194
17977
  .o-color-picker-widget {
17195
- display: inline-block;
17978
+ display: flex;
17196
17979
  position: relative;
17980
+ align-items: center;
17197
17981
 
17198
17982
  .o-color-picker-button-style {
17199
17983
  display: flex;
@@ -17209,6 +17993,7 @@ css /* scss */ `
17209
17993
  }
17210
17994
 
17211
17995
  .o-color-picker-button {
17996
+ height: 30px;
17212
17997
  > span {
17213
17998
  border-bottom: 4px solid;
17214
17999
  height: 16px;
@@ -19418,6 +20203,8 @@ class ContentEditableHelper {
19418
20203
  start = 0;
19419
20204
  if (end > textLength)
19420
20205
  end = textLength;
20206
+ if (start > textLength)
20207
+ start = textLength;
19421
20208
  }
19422
20209
  let startNode = this.findChildAtCharacterIndex(start);
19423
20210
  let endNode = this.findChildAtCharacterIndex(end);
@@ -19687,6 +20474,7 @@ css /* scss */ `
19687
20474
  padding-right: 2px;
19688
20475
 
19689
20476
  box-sizing: border-box;
20477
+ font-family: ${DEFAULT_FONT};
19690
20478
 
19691
20479
  caret-color: black;
19692
20480
  padding-left: 3px;
@@ -20129,7 +20917,7 @@ class Composer extends Component {
20129
20917
  const highlights = this.env.model.getters.getHighlights();
20130
20918
  const refSheet = sheetName
20131
20919
  ? this.env.model.getters.getSheetIdByName(sheetName)
20132
- : this.env.model.getters.getEditionSheet();
20920
+ : this.env.model.getters.getCurrentEditedCell().sheetId;
20133
20921
  const highlight = highlights.find((highlight) => {
20134
20922
  if (highlight.sheetId !== refSheet)
20135
20923
  return false;
@@ -20290,7 +21078,7 @@ class GridComposer extends Component {
20290
21078
  get cellReference() {
20291
21079
  const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
20292
21080
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
20293
- return `${prefixSheet ? getComposerSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
21081
+ return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
20294
21082
  }
20295
21083
  get cellReferenceStyle() {
20296
21084
  const { x: left, y: top } = this.rect;
@@ -20475,15 +21263,18 @@ function screenCoordinatesToInternal(getters, { x, y }) {
20475
21263
  return { x, y };
20476
21264
  }
20477
21265
 
20478
- function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { scrollX, scrollY }) {
21266
+ function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { maxX, maxY }, { scrollX, scrollY }) {
20479
21267
  const minX = viewportX ? 0 : -scrollX;
20480
21268
  const minY = viewportY ? 0 : -scrollY;
20481
- let deltaX = mouseX - mouseInitialX;
20482
- const newX = Math.max(initialFigure.x + deltaX, minX);
20483
- let deltaY = mouseY - mouseInitialY;
20484
- const newY = Math.max(initialFigure.y + deltaY, minY);
21269
+ const deltaX = mouseX - mouseInitialX;
21270
+ const newX = clamp(initialFigure.x + deltaX, minX, maxX - initialFigure.width - scrollX);
21271
+ const deltaY = mouseY - mouseInitialY;
21272
+ const newY = clamp(initialFigure.y + deltaY, minY, maxY - initialFigure.height - scrollY);
20485
21273
  return { ...initialFigure, x: newX, y: newY };
20486
21274
  }
21275
+ function clamp(value, min, max) {
21276
+ return Math.min(Math.max(value, min), max);
21277
+ }
20487
21278
  function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, keepRatio, minFigSize) {
20488
21279
  let { x, y, width, height } = initialFigure;
20489
21280
  if (keepRatio && dirX != 0 && dirY != 0) {
@@ -20882,12 +21673,16 @@ class FiguresContainer extends Component {
20882
21673
  }
20883
21674
  const sheetId = this.env.model.getters.getActiveSheetId();
20884
21675
  const initialMousePosition = { x: ev.clientX, y: ev.clientY };
21676
+ const maxDimensions = {
21677
+ maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
21678
+ maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
21679
+ };
20885
21680
  const { x, y } = internalFigureToScreen(this.env.model.getters, figure);
20886
21681
  const initialFig = { ...figure, x, y };
20887
21682
  const onMouseMove = (ev) => {
20888
21683
  const getters = this.env.model.getters;
20889
21684
  const currentMousePosition = { x: ev.clientX, y: ev.clientY };
20890
- const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), getters.getActiveSheetScrollInfo());
21685
+ const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), maxDimensions, getters.getActiveSheetScrollInfo());
20891
21686
  const otherFigures = this.getOtherFigures(figure.id);
20892
21687
  const internalDragged = screenFigureToInternal(getters, draggedFigure);
20893
21688
  const snapResult = snapForMove(getters, internalDragged, otherFigures);
@@ -21217,6 +22012,10 @@ GridOverlay.props = {
21217
22012
  };
21218
22013
 
21219
22014
  class GridPopover extends Component {
22015
+ constructor() {
22016
+ super(...arguments);
22017
+ this.zIndex = ComponentsImportance.GridPopover;
22018
+ }
21220
22019
  get cellPopover() {
21221
22020
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
21222
22021
  if (!popover.isOpen) {
@@ -22581,6 +23380,10 @@ class Grid extends Component {
22581
23380
  }
22582
23381
  }
22583
23382
  onInput(ev) {
23383
+ // the user meant to paste in the sheet, not open the composer with the pasted content
23384
+ if (!ev.isComposing && ev.inputType === "insertFromPaste") {
23385
+ return;
23386
+ }
22584
23387
  if (ev.data) {
22585
23388
  // if the user types a character on the grid, it means he wants to start composing the selected cell with that
22586
23389
  // character
@@ -23429,68 +24232,7 @@ function fixXlsxUnicode(str) {
23429
24232
  });
23430
24233
  }
23431
24234
 
23432
- function convertBorders(data, warningManager) {
23433
- const borderArray = data.borders.map((border) => {
23434
- addBorderWarnings(border, warningManager);
23435
- const b = {
23436
- top: convertBorderDescr$1(border.top, warningManager),
23437
- bottom: convertBorderDescr$1(border.bottom, warningManager),
23438
- left: convertBorderDescr$1(border.left, warningManager),
23439
- right: convertBorderDescr$1(border.right, warningManager),
23440
- };
23441
- Object.keys(b).forEach((key) => b[key] === undefined && delete b[key]);
23442
- return b;
23443
- });
23444
- return arrayToObject(borderArray, 1);
23445
- }
23446
- function convertBorderDescr$1(borderDescr, warningManager) {
23447
- if (!borderDescr)
23448
- return undefined;
23449
- addBorderDescrWarnings(borderDescr, warningManager);
23450
- const style = BORDER_STYLE_CONVERSION_MAP[borderDescr.style];
23451
- return style ? [style, convertColor(borderDescr.color)] : undefined;
23452
- }
23453
- function convertStyles(data, warningManager) {
23454
- const stylesArray = data.styles.map((style) => {
23455
- return convertStyle({
23456
- fontStyle: data.fonts[style.fontId],
23457
- fillStyle: data.fills[style.fillId],
23458
- alignment: style.alignment,
23459
- }, warningManager);
23460
- });
23461
- return arrayToObject(stylesArray, 1);
23462
- }
23463
- function convertStyle(styleStruct, warningManager) {
23464
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
23465
- addStyleWarnings(styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.fontStyle, styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.fillStyle, warningManager);
23466
- addHorizontalAlignmentWarnings((_a = styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.alignment) === null || _a === void 0 ? void 0 : _a.horizontal, warningManager);
23467
- addVerticalAlignmentWarnings((_b = styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.alignment) === null || _b === void 0 ? void 0 : _b.vertical, warningManager);
23468
- return {
23469
- bold: (_c = styleStruct.fontStyle) === null || _c === void 0 ? void 0 : _c.bold,
23470
- italic: (_d = styleStruct.fontStyle) === null || _d === void 0 ? void 0 : _d.italic,
23471
- strikethrough: (_e = styleStruct.fontStyle) === null || _e === void 0 ? void 0 : _e.strike,
23472
- underline: (_f = styleStruct.fontStyle) === null || _f === void 0 ? void 0 : _f.underline,
23473
- align: ((_g = styleStruct.alignment) === null || _g === void 0 ? void 0 : _g.horizontal)
23474
- ? H_ALIGNMENT_CONVERSION_MAP[styleStruct.alignment.horizontal]
23475
- : undefined,
23476
- // In xlsx fills, bgColor is the color of the fill, and fgColor is the color of the pattern above the background, except in solid fills
23477
- fillColor: ((_h = styleStruct.fillStyle) === null || _h === void 0 ? void 0 : _h.patternType) === "solid"
23478
- ? convertColor((_j = styleStruct.fillStyle) === null || _j === void 0 ? void 0 : _j.fgColor)
23479
- : convertColor((_k = styleStruct.fillStyle) === null || _k === void 0 ? void 0 : _k.bgColor),
23480
- textColor: convertColor((_l = styleStruct.fontStyle) === null || _l === void 0 ? void 0 : _l.color),
23481
- fontSize: (_m = styleStruct.fontStyle) === null || _m === void 0 ? void 0 : _m.size,
23482
- };
23483
- }
23484
- function convertFormats(data, warningManager) {
23485
- const formats = [];
23486
- for (let style of data.styles) {
23487
- const format = convertXlsxFormat(style.numFmtId, data.numFmts, warningManager);
23488
- if (format) {
23489
- formats[style.numFmtId] = format;
23490
- }
23491
- }
23492
- return arrayToObject(formats, 1);
23493
- }
24235
+ 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;
23494
24236
  /**
23495
24237
  * Convert excel format to o_spreadsheet format
23496
24238
  *
@@ -23515,17 +24257,107 @@ function convertXlsxFormat(numFmtId, formats, warningManager) {
23515
24257
  throw new Error("Multiple escaped blocks in format");
23516
24258
  }
23517
24259
  convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23518
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
24260
+ convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
23519
24261
  convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23520
24262
  convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23521
- formatValue(0, convertedFormat);
23522
- return convertedFormat;
24263
+ convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
24264
+ if (isXlsxDateFormat(convertedFormat)) {
24265
+ convertedFormat = convertDateFormat$1(convertedFormat);
24266
+ }
24267
+ if (isFormatSupported(convertedFormat)) {
24268
+ return convertedFormat;
24269
+ }
23523
24270
  }
23524
24271
  catch (e) { }
23525
24272
  }
23526
24273
  warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23527
24274
  return undefined;
23528
24275
  }
24276
+ function isFormatSupported(format) {
24277
+ try {
24278
+ formatValue(0, format);
24279
+ return true;
24280
+ }
24281
+ catch (e) {
24282
+ return false;
24283
+ }
24284
+ }
24285
+ function isXlsxDateFormat(format) {
24286
+ return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
24287
+ }
24288
+ function convertDateFormat$1(format) {
24289
+ // Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
24290
+ // but can still occur and are supported by Excel/Google sheets
24291
+ format = format.toLowerCase();
24292
+ format = format.replace(/mmmmm/g, "mmm");
24293
+ format = format.replace(/am\/pm|a\/m/g, "a");
24294
+ format = format.replace(/hhhh/g, "hh");
24295
+ format = format.replace(/\bh\b/g, "hh");
24296
+ return format;
24297
+ }
24298
+
24299
+ function convertBorders(data, warningManager) {
24300
+ const borderArray = data.borders.map((border) => {
24301
+ addBorderWarnings(border, warningManager);
24302
+ const b = {
24303
+ top: convertBorderDescr$1(border.top, warningManager),
24304
+ bottom: convertBorderDescr$1(border.bottom, warningManager),
24305
+ left: convertBorderDescr$1(border.left, warningManager),
24306
+ right: convertBorderDescr$1(border.right, warningManager),
24307
+ };
24308
+ Object.keys(b).forEach((key) => b[key] === undefined && delete b[key]);
24309
+ return b;
24310
+ });
24311
+ return arrayToObject(borderArray, 1);
24312
+ }
24313
+ function convertBorderDescr$1(borderDescr, warningManager) {
24314
+ if (!borderDescr)
24315
+ return undefined;
24316
+ addBorderDescrWarnings(borderDescr, warningManager);
24317
+ const style = BORDER_STYLE_CONVERSION_MAP[borderDescr.style];
24318
+ return style ? [style, convertColor(borderDescr.color)] : undefined;
24319
+ }
24320
+ function convertStyles(data, warningManager) {
24321
+ const stylesArray = data.styles.map((style) => {
24322
+ return convertStyle({
24323
+ fontStyle: data.fonts[style.fontId],
24324
+ fillStyle: data.fills[style.fillId],
24325
+ alignment: style.alignment,
24326
+ }, warningManager);
24327
+ });
24328
+ return arrayToObject(stylesArray, 1);
24329
+ }
24330
+ function convertStyle(styleStruct, warningManager) {
24331
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
24332
+ addStyleWarnings(styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.fontStyle, styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.fillStyle, warningManager);
24333
+ addHorizontalAlignmentWarnings((_a = styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.alignment) === null || _a === void 0 ? void 0 : _a.horizontal, warningManager);
24334
+ addVerticalAlignmentWarnings((_b = styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.alignment) === null || _b === void 0 ? void 0 : _b.vertical, warningManager);
24335
+ return {
24336
+ bold: (_c = styleStruct.fontStyle) === null || _c === void 0 ? void 0 : _c.bold,
24337
+ italic: (_d = styleStruct.fontStyle) === null || _d === void 0 ? void 0 : _d.italic,
24338
+ strikethrough: (_e = styleStruct.fontStyle) === null || _e === void 0 ? void 0 : _e.strike,
24339
+ underline: (_f = styleStruct.fontStyle) === null || _f === void 0 ? void 0 : _f.underline,
24340
+ align: ((_g = styleStruct.alignment) === null || _g === void 0 ? void 0 : _g.horizontal)
24341
+ ? H_ALIGNMENT_CONVERSION_MAP[styleStruct.alignment.horizontal]
24342
+ : undefined,
24343
+ // In xlsx fills, bgColor is the color of the fill, and fgColor is the color of the pattern above the background, except in solid fills
24344
+ fillColor: ((_h = styleStruct.fillStyle) === null || _h === void 0 ? void 0 : _h.patternType) === "solid"
24345
+ ? convertColor((_j = styleStruct.fillStyle) === null || _j === void 0 ? void 0 : _j.fgColor)
24346
+ : convertColor((_k = styleStruct.fillStyle) === null || _k === void 0 ? void 0 : _k.bgColor),
24347
+ textColor: convertColor((_l = styleStruct.fontStyle) === null || _l === void 0 ? void 0 : _l.color),
24348
+ fontSize: (_m = styleStruct.fontStyle) === null || _m === void 0 ? void 0 : _m.size,
24349
+ };
24350
+ }
24351
+ function convertFormats(data, warningManager) {
24352
+ const formats = [];
24353
+ for (let style of data.styles) {
24354
+ const format = convertXlsxFormat(style.numFmtId, data.numFmts, warningManager);
24355
+ if (format) {
24356
+ formats[style.numFmtId] = format;
24357
+ }
24358
+ }
24359
+ return arrayToObject(formats, 1);
24360
+ }
23529
24361
  // ---------------------------------------------------------------------------
23530
24362
  // Warnings
23531
24363
  // ---------------------------------------------------------------------------
@@ -24080,16 +24912,18 @@ function convertFigure(figure, id, sheetData) {
24080
24912
  };
24081
24913
  }
24082
24914
  function convertChartData(chartData) {
24083
- var _a;
24084
- const labelRange = (_a = chartData.dataSets[0].label) === null || _a === void 0 ? void 0 : _a.replace(/\$/g, "");
24085
- let dataSets = chartData.dataSets.map((data) => data.range.replace(/\$/g, ""));
24915
+ const dataSetsHaveTitle = chartData.dataSets[0].label !== undefined;
24916
+ const labelRange = chartData.labelRange
24917
+ ? convertExcelRangeToSheetXC(chartData.labelRange, dataSetsHaveTitle)
24918
+ : undefined;
24919
+ let dataSets = chartData.dataSets.map((data) => convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle));
24086
24920
  // For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
24087
24921
  if (chartData.type === "pie") {
24088
24922
  dataSets.reverse();
24089
24923
  }
24090
24924
  return {
24091
24925
  dataSets,
24092
- dataSetsHaveTitle: false,
24926
+ dataSetsHaveTitle,
24093
24927
  labelRange,
24094
24928
  title: chartData.title || "",
24095
24929
  type: chartData.type,
@@ -24100,6 +24934,28 @@ function convertChartData(chartData) {
24100
24934
  aggregated: false,
24101
24935
  labelsAsText: false,
24102
24936
  };
24937
+ }
24938
+ function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
24939
+ let { sheetName, xc } = splitReference(range);
24940
+ if (sheetName) {
24941
+ sheetName = getCanonicalSheetName(sheetName) + "!";
24942
+ }
24943
+ else {
24944
+ sheetName = "";
24945
+ }
24946
+ let zone = toUnboundedZone(xc);
24947
+ if (dataSetsHaveTitle && zone.bottom !== undefined && zone.right !== undefined) {
24948
+ const height = zone.bottom - zone.top + 1;
24949
+ const width = zone.right - zone.left + 1;
24950
+ if (height === 1) {
24951
+ zone = { ...zone, left: zone.left - 1 };
24952
+ }
24953
+ else if (width === 1) {
24954
+ zone = { ...zone, top: zone.top - 1 };
24955
+ }
24956
+ }
24957
+ const dataXC = zoneToXc(zone);
24958
+ return sheetName + dataXC;
24103
24959
  }
24104
24960
 
24105
24961
  /**
@@ -25167,6 +26023,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
25167
26023
  title: chartTitle,
25168
26024
  type: CHART_TYPE_CONVERSION_MAP[chartType],
25169
26025
  dataSets: this.extractChartDatasets(this.querySelector(rootChartElement, `c:${chartType}`)),
26026
+ labelRange: this.extractChildTextContent(rootChartElement, "c:ser c:cat c:f"),
25170
26027
  backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
25171
26028
  default: "ffffff",
25172
26029
  }).asString(),
@@ -25186,7 +26043,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
25186
26043
  extractChartDatasets(chartElement) {
25187
26044
  return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
25188
26045
  return {
25189
- label: this.extractChildTextContent(chartDataElement, "c:cat c:f"),
26046
+ label: this.extractChildTextContent(chartDataElement, "c:tx c:f"),
25190
26047
  range: this.extractChildTextContent(chartDataElement, "c:val c:f", { required: true }),
25191
26048
  };
25192
26049
  });
@@ -29103,6 +29960,39 @@ class FigurePlugin extends CorePlugin {
29103
29960
  case "DELETE_FIGURE":
29104
29961
  this.removeFigure(cmd.id, cmd.sheetId);
29105
29962
  break;
29963
+ case "REMOVE_COLUMNS_ROWS":
29964
+ this.onRowColDelete(cmd.sheetId, cmd.dimension);
29965
+ }
29966
+ }
29967
+ onRowColDelete(sheetId, dimension) {
29968
+ dimension === "ROW" ? this.onRowDeletion(sheetId) : this.onColDeletion(sheetId);
29969
+ }
29970
+ onRowDeletion(sheetId) {
29971
+ const numHeader = this.getters.getNumberRows(sheetId);
29972
+ let gridHeight = 0;
29973
+ for (let i = 0; i < numHeader; i++) {
29974
+ gridHeight += this.getters.getRowSize(sheetId, i);
29975
+ }
29976
+ const figures = this.getters.getFigures(sheetId);
29977
+ for (const figure of figures) {
29978
+ const newY = Math.min(figure.y, gridHeight - figure.height);
29979
+ if (newY !== figure.y) {
29980
+ this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, y: newY });
29981
+ }
29982
+ }
29983
+ }
29984
+ onColDeletion(sheetId) {
29985
+ const numHeader = this.getters.getNumberCols(sheetId);
29986
+ let gridWidth = 0;
29987
+ for (let i = 0; i < numHeader; i++) {
29988
+ gridWidth += this.getters.getColSize(sheetId, i);
29989
+ }
29990
+ const figures = this.getters.getFigures(sheetId);
29991
+ for (const figure of figures) {
29992
+ const newX = Math.min(figure.x, gridWidth - figure.width);
29993
+ if (newX !== figure.x) {
29994
+ this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x: newX });
29995
+ }
29106
29996
  }
29107
29997
  }
29108
29998
  updateFigure(sheetId, figure) {
@@ -30773,7 +31663,7 @@ class RangeAdapter {
30773
31663
  sheetName = rangeImpl.invalidSheetName;
30774
31664
  }
30775
31665
  else {
30776
- sheetName = getComposerSheetName(this.getters.getSheetName(rangeImpl.sheetId));
31666
+ sheetName = getCanonicalSheetName(this.getters.getSheetName(rangeImpl.sheetId));
30777
31667
  }
30778
31668
  }
30779
31669
  if (prefixSheet && !sheetName) {
@@ -31824,9 +32714,7 @@ class CustomColorsPlugin extends UIPlugin {
31824
32714
  // remove duplicates first to check validity on a reduced
31825
32715
  // set of colors, then normalize to HEX and remove duplicates
31826
32716
  // again
31827
- [...new Set([...usedColors, ...this.customColors])]
31828
- .filter(isColorValid)
31829
- .map((c) => toHex(c).toLowerCase())),
32717
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
31830
32718
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
31831
32719
  }
31832
32720
  getColorsFromCells(cells) {
@@ -31887,7 +32775,7 @@ class CustomColorsPlugin extends UIPlugin {
31887
32775
  return [...chartsColors];
31888
32776
  }
31889
32777
  tryToAddColor(color) {
31890
- const formattedColor = toHex(color).toLowerCase();
32778
+ const formattedColor = toHex(color);
31891
32779
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
31892
32780
  this.customColors.add(formattedColor);
31893
32781
  }
@@ -32902,8 +33790,8 @@ class InternalViewport {
32902
33790
  this.getters = getters;
32903
33791
  this.sheetId = sheetId;
32904
33792
  this.boundaries = boundaries;
32905
- this.width = sizeInGrid.width;
32906
- this.height = sizeInGrid.height;
33793
+ this.viewportWidth = sizeInGrid.width;
33794
+ this.viewportHeight = sizeInGrid.height;
32907
33795
  this.offsetScrollbarX = offsets.x;
32908
33796
  this.offsetScrollbarY = offsets.y;
32909
33797
  this.canScrollVertically = options.canScrollVertically;
@@ -32914,6 +33802,10 @@ class InternalViewport {
32914
33802
  this.adjustViewportOffsetY();
32915
33803
  }
32916
33804
  // PUBLIC
33805
+ /** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
33806
+ * When the viewport grid size is smaller than its client width (resp. height), it will return
33807
+ * the client width (resp. height).
33808
+ */
32917
33809
  getMaxSize() {
32918
33810
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
32919
33811
  first: this.boundaries.left,
@@ -32925,20 +33817,24 @@ class InternalViewport {
32925
33817
  });
32926
33818
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
32927
33819
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
32928
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
33820
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
32929
33821
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
32930
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
33822
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
32931
33823
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
32932
- const width = lastColEnd -
32933
- this.offsetCorrectionX +
32934
- (this.canScrollHorizontally
32935
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
32936
- : 0);
32937
- const height = lastRowEnd -
32938
- this.offsetCorrectionY +
32939
- (this.canScrollVertically
32940
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
32941
- : 0);
33824
+ let width = lastColEnd - this.offsetCorrectionX;
33825
+ if (this.canScrollHorizontally) {
33826
+ width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
33827
+ Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
33828
+ );
33829
+ width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
33830
+ }
33831
+ let height = lastRowEnd - this.offsetCorrectionY;
33832
+ if (this.canScrollVertically) {
33833
+ height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
33834
+ Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
33835
+ );
33836
+ height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
33837
+ }
32942
33838
  return { width, height };
32943
33839
  }
32944
33840
  /**
@@ -32947,7 +33843,7 @@ class InternalViewport {
32947
33843
  * It returns -1 if no column is found.
32948
33844
  */
32949
33845
  getColIndex(x, absolute = false) {
32950
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
33846
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
32951
33847
  return -1;
32952
33848
  }
32953
33849
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -32958,7 +33854,7 @@ class InternalViewport {
32958
33854
  * It returns -1 if no row is found.
32959
33855
  */
32960
33856
  getRowIndex(y, absolute = false) {
32961
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
33857
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
32962
33858
  return -1;
32963
33859
  }
32964
33860
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -32982,48 +33878,66 @@ class InternalViewport {
32982
33878
  this.adjustPositionY(row);
32983
33879
  }
32984
33880
  }
32985
- adjustPositionX(col) {
33881
+ adjustPositionX(targetCol) {
32986
33882
  const sheetId = this.sheetId;
32987
- const { start, end } = this.getters.getColDimensions(sheetId, col);
32988
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
32989
- this.offsetX + this.offsetCorrectionX < start) {
32990
- this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
32991
- this.offsetScrollbarX = this.offsetX;
32992
- this.adjustViewportZoneX();
32993
- }
32994
- while (col < this.left) {
32995
- let leftCol;
32996
- for (leftCol = this.left; leftCol >= 0; leftCol--) {
32997
- if (!this.getters.isColHidden(sheetId, leftCol)) {
33883
+ const { end } = this.getters.getColDimensions(sheetId, targetCol);
33884
+ const maxCol = this.getters.getNumberCols(sheetId);
33885
+ if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
33886
+ for (let col = this.left; this.offsetX + this.offsetCorrectionX + this.viewportWidth < end; col++) {
33887
+ if (col > maxCol) {
33888
+ break;
33889
+ }
33890
+ if (this.getters.isColHidden(sheetId, col)) {
33891
+ continue;
33892
+ }
33893
+ this.offsetX = this.getters.getColDimensions(sheetId, col).end - this.offsetCorrectionX;
33894
+ this.offsetScrollbarX = this.offsetX;
33895
+ this.adjustViewportZoneX();
33896
+ }
33897
+ }
33898
+ else if (this.left > targetCol) {
33899
+ for (let col = this.left; col >= targetCol; col--) {
33900
+ if (col < 0) {
32998
33901
  break;
32999
33902
  }
33903
+ if (this.getters.isColHidden(sheetId, col)) {
33904
+ continue;
33905
+ }
33906
+ this.offsetX = this.getters.getColDimensions(sheetId, col).start - this.offsetCorrectionX;
33907
+ this.offsetScrollbarX = this.offsetX;
33908
+ this.adjustViewportZoneX();
33000
33909
  }
33001
- this.offsetX =
33002
- this.getters.getColDimensions(sheetId, leftCol - 1).start - this.offsetCorrectionX;
33003
- this.offsetScrollbarX = this.offsetX;
33004
- this.adjustViewportZoneX();
33005
33910
  }
33006
33911
  }
33007
- adjustPositionY(row) {
33912
+ adjustPositionY(targetRow) {
33008
33913
  const sheetId = this.sheetId;
33009
- while (this.getters.getRowDimensions(sheetId, row).end >
33010
- this.offsetY + this.height + this.offsetCorrectionY &&
33011
- this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
33012
- this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
33013
- this.offsetScrollbarY = this.offsetY;
33014
- this.adjustViewportZoneY();
33015
- }
33016
- while (row < this.top) {
33017
- let topRow;
33018
- for (topRow = this.top; topRow >= 0; topRow--) {
33019
- if (!this.getters.isRowHidden(sheetId, topRow)) {
33914
+ const { end } = this.getters.getRowDimensions(sheetId, targetRow);
33915
+ const maxRow = this.getters.getNumberRows(sheetId);
33916
+ if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
33917
+ for (let row = this.top; this.offsetY + this.viewportHeight + this.offsetCorrectionY < end; row++) {
33918
+ if (row > maxRow) {
33919
+ break;
33920
+ }
33921
+ if (this.getters.isRowHidden(sheetId, row)) {
33922
+ continue;
33923
+ }
33924
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).end - this.offsetCorrectionY;
33925
+ this.offsetScrollbarY = this.offsetY;
33926
+ this.adjustViewportZoneY();
33927
+ }
33928
+ }
33929
+ else if (this.top > targetRow) {
33930
+ for (let row = this.top; row >= targetRow; row--) {
33931
+ if (row < 0) {
33020
33932
  break;
33021
33933
  }
33934
+ if (this.getters.isRowHidden(sheetId, row)) {
33935
+ continue;
33936
+ }
33937
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).start - this.offsetCorrectionY;
33938
+ this.offsetScrollbarY = this.offsetY;
33939
+ this.adjustViewportZoneY();
33022
33940
  }
33023
- this.offsetY =
33024
- this.getters.getRowDimensions(sheetId, topRow - 1).start - this.offsetCorrectionY;
33025
- this.offsetScrollbarY = this.offsetY;
33026
- this.adjustViewportZoneY();
33027
33941
  }
33028
33942
  }
33029
33943
  setViewportOffset(offsetX, offsetY) {
@@ -33045,8 +33959,8 @@ class InternalViewport {
33045
33959
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
33046
33960
  this.offsetCorrectionX;
33047
33961
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
33048
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
33049
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
33962
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
33963
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
33050
33964
  return {
33051
33965
  x,
33052
33966
  y,
@@ -33109,12 +34023,12 @@ class InternalViewport {
33109
34023
  adjustViewportOffsetX() {
33110
34024
  if (this.canScrollHorizontally) {
33111
34025
  const { width: viewportWidth } = this.getMaxSize();
33112
- if (this.width + this.offsetScrollbarX > viewportWidth) {
33113
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
34026
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
34027
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
33114
34028
  }
33115
34029
  }
33116
34030
  this.left = this.getColIndex(this.offsetScrollbarX, true);
33117
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
34031
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
33118
34032
  if (this.right === -1) {
33119
34033
  this.right = this.boundaries.right;
33120
34034
  }
@@ -33126,12 +34040,12 @@ class InternalViewport {
33126
34040
  adjustViewportOffsetY() {
33127
34041
  if (this.canScrollVertically) {
33128
34042
  const { height: paneHeight } = this.getMaxSize();
33129
- if (this.height + this.offsetScrollbarY > paneHeight) {
33130
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
34043
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
34044
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
33131
34045
  }
33132
34046
  }
33133
34047
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
33134
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
34048
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
33135
34049
  if (this.bottom === -1) {
33136
34050
  this.bottom = this.boundaries.bottom;
33137
34051
  }
@@ -33142,7 +34056,7 @@ class InternalViewport {
33142
34056
  adjustViewportZoneX() {
33143
34057
  const sheetId = this.sheetId;
33144
34058
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
33145
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
34059
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
33146
34060
  if (this.right === -1) {
33147
34061
  this.right = this.getters.getNumberCols(sheetId) - 1;
33148
34062
  }
@@ -33155,7 +34069,7 @@ class InternalViewport {
33155
34069
  adjustViewportZoneY() {
33156
34070
  const sheetId = this.sheetId;
33157
34071
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
33158
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
34072
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
33159
34073
  if (this.bottom === -1) {
33160
34074
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
33161
34075
  }
@@ -33216,8 +34130,8 @@ class SheetViewPlugin extends UIPlugin {
33216
34130
  * In the absence of a component (standalone model), is it mandatory to set reasonable default values
33217
34131
  * to ensure the correct operation of this plugin.
33218
34132
  */
33219
- this.sheetViewWidth = DEFAULT_SHEETVIEW_SIZE;
33220
- this.sheetViewHeight = DEFAULT_SHEETVIEW_SIZE;
34133
+ this.sheetViewWidth = getDefaultSheetViewSize();
34134
+ this.sheetViewHeight = getDefaultSheetViewSize();
33221
34135
  this.gridOffsetX = 0;
33222
34136
  this.gridOffsetY = 0;
33223
34137
  this.sheetsWithDirtyViewports = new Set();
@@ -33418,8 +34332,7 @@ class SheetViewPlugin extends UIPlugin {
33418
34332
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
33419
34333
  }
33420
34334
  /**
33421
- * Return the main viewport maximum size. That is the zone dimension
33422
- * with some bottom and right padding.
34335
+ * Return the main viewport maximum size relative to the client size.
33423
34336
  */
33424
34337
  getMainViewportRect() {
33425
34338
  const sheetId = this.getters.getActiveSheetId();
@@ -33435,8 +34348,8 @@ class SheetViewPlugin extends UIPlugin {
33435
34348
  const { width, height } = this.getMainViewportRect();
33436
34349
  const viewport = this.getMainInternalViewport(sheetId);
33437
34350
  return {
33438
- maxOffsetX: Math.max(0, width - viewport.width + 1),
33439
- maxOffsetY: Math.max(0, height - viewport.height + 1),
34351
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
34352
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
33440
34353
  };
33441
34354
  }
33442
34355
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -35656,7 +36569,7 @@ class SelectionInputPlugin extends UIPlugin {
35656
36569
  const inputSheetId = this.activeSheet;
35657
36570
  const sheetId = this.getters.getActiveSheetId();
35658
36571
  const sheetName = this.getters.getSheetName(sheetId);
35659
- this.add([sheetId === inputSheetId ? xc : `${getComposerSheetName(sheetName)}!${xc}`]);
36572
+ this.add([sheetId === inputSheetId ? xc : `${getCanonicalSheetName(sheetName)}!${xc}`]);
35660
36573
  }
35661
36574
  handle(cmd) {
35662
36575
  switch (cmd.type) {
@@ -37903,13 +38816,19 @@ class ClipboardFigureState {
37903
38816
  */
37904
38817
  paste(target) {
37905
38818
  const sheetId = this.getters.getActiveSheetId();
38819
+ const { width, height } = this.copiedFigure;
38820
+ const numCols = this.getters.getNumberCols(sheetId);
38821
+ const numRows = this.getters.getNumberRows(sheetId);
38822
+ const targetX = this.getters.getColDimensions(sheetId, target[0].left).start;
38823
+ const targetY = this.getters.getRowDimensions(sheetId, target[0].top).start;
38824
+ const maxX = this.getters.getColDimensions(sheetId, numCols - 1).end;
38825
+ const maxY = this.getters.getRowDimensions(sheetId, numRows - 1).end;
37906
38826
  const position = {
37907
- x: this.getters.getColDimensions(sheetId, target[0].left).start,
37908
- y: this.getters.getRowDimensions(sheetId, target[0].top).start,
38827
+ x: maxX < width ? 0 : Math.min(targetX, maxX - width),
38828
+ y: maxY < height ? 0 : Math.min(targetY, maxY - height),
37909
38829
  };
37910
- const size = { height: this.copiedFigure.height, width: this.copiedFigure.width };
37911
38830
  const newId = new UuidGenerator().uuidv4();
37912
- this.copiedFigureContent.paste(sheetId, newId, position, size);
38831
+ this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
37913
38832
  if (this.operation === "CUT") {
37914
38833
  this.dispatch("DELETE_FIGURE", {
37915
38834
  sheetId: this.copiedFigureContent.sheetId,
@@ -38275,7 +39194,7 @@ function loopThroughReferenceType(token) {
38275
39194
  return token;
38276
39195
  const { xc, sheetName } = splitReference(token.value);
38277
39196
  const [left, right] = xc.split(":");
38278
- const sheetRef = sheetName ? `${getComposerSheetName(sheetName)}!` : "";
39197
+ const sheetRef = sheetName ? `${getCanonicalSheetName(sheetName)}!` : "";
38279
39198
  const updatedLeft = getTokenNextReferenceType(left);
38280
39199
  const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
38281
39200
  return { ...token, value: sheetRef + updatedLeft + updatedRight };
@@ -38534,9 +39453,6 @@ class EditionPlugin extends UIPlugin {
38534
39453
  }
38535
39454
  return this.currentContent;
38536
39455
  }
38537
- getEditionSheet() {
38538
- return this.sheetId;
38539
- }
38540
39456
  getComposerSelection() {
38541
39457
  return {
38542
39458
  start: this.selectionStart,
@@ -38820,8 +39736,8 @@ class EditionPlugin extends UIPlugin {
38820
39736
  getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
38821
39737
  const sheetId = this.getters.getActiveSheetId();
38822
39738
  let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
38823
- if (this.getters.getEditionSheet() !== this.getters.getActiveSheetId()) {
38824
- const sheetName = getComposerSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
39739
+ if (this.getters.getCurrentEditedCell().sheetId !== this.getters.getActiveSheetId()) {
39740
+ const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
38825
39741
  selectedXc = `${sheetName}!${selectedXc}`;
38826
39742
  }
38827
39743
  return selectedXc;
@@ -38835,7 +39751,7 @@ class EditionPlugin extends UIPlugin {
38835
39751
  _fixedParts.pop();
38836
39752
  }
38837
39753
  const newRange = range.clone({ parts: _fixedParts });
38838
- return this.getters.getSelectionRangeString(newRange, this.getters.getEditionSheet());
39754
+ return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().sheetId);
38839
39755
  }
38840
39756
  /**
38841
39757
  * Replace the current selection by a new text.
@@ -38868,7 +39784,7 @@ class EditionPlugin extends UIPlugin {
38868
39784
  if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
38869
39785
  return;
38870
39786
  }
38871
- const editionSheetId = this.getters.getEditionSheet();
39787
+ const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
38872
39788
  const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
38873
39789
  const colorsToKeep = {};
38874
39790
  for (const xc of XCs) {
@@ -38897,7 +39813,7 @@ class EditionPlugin extends UIPlugin {
38897
39813
  if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
38898
39814
  return [];
38899
39815
  }
38900
- const editionSheetId = this.getters.getEditionSheet();
39816
+ const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
38901
39817
  const rangeColor = (rangeString) => {
38902
39818
  const colorIndex = this.colorIndexByRange[rangeString];
38903
39819
  return colors$1[colorIndex % colors$1.length];
@@ -38915,7 +39831,7 @@ class EditionPlugin extends UIPlugin {
38915
39831
  * Return ranges currently referenced in the composer
38916
39832
  */
38917
39833
  getReferencedRanges() {
38918
- const editionSheetId = this.getters.getEditionSheet();
39834
+ const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
38919
39835
  return this.currentTokens
38920
39836
  .filter((token) => token.type === "REFERENCE")
38921
39837
  .map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
@@ -38974,7 +39890,6 @@ EditionPlugin.getters = [
38974
39890
  "isSelectingForComposer",
38975
39891
  "showSelectionIndicator",
38976
39892
  "getCurrentContent",
38977
- "getEditionSheet",
38978
39893
  "getComposerSelection",
38979
39894
  "getCurrentTokens",
38980
39895
  "getTokenAtCursor",
@@ -39647,7 +40562,7 @@ const coreViewsPluginRegistry = new Registry()
39647
40562
  const clickableCellRegistry = new Registry();
39648
40563
  clickableCellRegistry.add("link", {
39649
40564
  condition: (position, env) => !!env.model.getters.getEvaluatedCell(position).link,
39650
- action: (position, env) => openLink(env.model.getters.getEvaluatedCell(position).link, env),
40565
+ execute: (position, env) => openLink(env.model.getters.getEvaluatedCell(position).link, env),
39651
40566
  sequence: 5,
39652
40567
  });
39653
40568
 
@@ -40104,7 +41019,7 @@ class BottomBarStatistic extends Component {
40104
41019
  name: this.getComposedFnName(fnName, fnValue),
40105
41020
  sequence: i,
40106
41021
  isReadonlyAllowed: true,
40107
- action: () => {
41022
+ execute: () => {
40108
41023
  this.selectedStatisticFn = fnName;
40109
41024
  },
40110
41025
  });
@@ -40272,10 +41187,6 @@ css /* scss */ `
40272
41187
  font-size: 15px;
40273
41188
  border-top: 1px solid lightgrey;
40274
41189
 
40275
- .o-add-sheet.disabled {
40276
- cursor: not-allowed;
40277
- }
40278
-
40279
41190
  .o-sheet-item {
40280
41191
  cursor: pointer;
40281
41192
  &:hover {
@@ -40297,10 +41208,6 @@ css /* scss */ `
40297
41208
  .o-bottom-bar-arrows {
40298
41209
  .o-bottom-bar-arrow {
40299
41210
  cursor: pointer;
40300
- &.o-disabled {
40301
- opacity: 0.4;
40302
- cursor: default;
40303
- }
40304
41211
  &:hover:not([class*="o-disabled"]) {
40305
41212
  .o-icon {
40306
41213
  opacity: 0.9;
@@ -40385,7 +41292,7 @@ class BottomBar extends Component {
40385
41292
  sequence: i,
40386
41293
  isReadonlyAllowed: true,
40387
41294
  textColor: sheet.isVisible ? undefined : "grey",
40388
- action: (env) => {
41295
+ execute: (env) => {
40389
41296
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: from, sheetIdTo: sheetId });
40390
41297
  },
40391
41298
  });
@@ -40642,7 +41549,7 @@ class SpreadsheetDashboard extends Component {
40642
41549
  getClickableAction(position) {
40643
41550
  for (const items of clickableCellRegistry.getAll().sort((a, b) => a.sequence - b.sequence)) {
40644
41551
  if (items.condition(position, this.env)) {
40645
- return items.action;
41552
+ return items.execute;
40646
41553
  }
40647
41554
  }
40648
41555
  return false;
@@ -40870,21 +41777,66 @@ SidePanel.props = {
40870
41777
  onCloseSidePanel: Function,
40871
41778
  };
40872
41779
 
40873
- const AddMergeInteractiveContent = {
40874
- MergeIsDestructive: _lt("Merging these cells will only preserve the top-leftmost value. Merge anyway?"),
40875
- MergeInFilter: _lt("You can't merge cells inside of an existing filter."),
40876
- };
40877
- function interactiveAddMerge(env, sheetId, target) {
40878
- const result = env.model.dispatch("ADD_MERGE", { sheetId, target });
40879
- if (result.isCancelledBecause(80 /* CommandResult.MergeInFilter */)) {
40880
- env.raiseError(AddMergeInteractiveContent.MergeInFilter);
41780
+ css /* scss */ `
41781
+ .o-menu-item-button {
41782
+ display: flex;
41783
+ justify-content: center;
41784
+ align-items: center;
41785
+ margin: 2px;
41786
+ padding: 0px 3px;
41787
+ border-radius: 2px;
41788
+ min-width: 20px;
41789
+ }
41790
+ .o-disabled {
41791
+ opacity: 0.6;
41792
+ cursor: default;
41793
+ }
41794
+ `;
41795
+ class ActionButton extends Component {
41796
+ constructor() {
41797
+ super(...arguments);
41798
+ this.actionButton = createAction(this.props.action);
40881
41799
  }
40882
- else if (result.isCancelledBecause(3 /* CommandResult.MergeIsDestructive */)) {
40883
- env.askConfirmation(AddMergeInteractiveContent.MergeIsDestructive, () => {
40884
- env.model.dispatch("ADD_MERGE", { sheetId, target, force: true });
40885
- });
41800
+ setup() {
41801
+ onWillUpdateProps(() => (this.actionButton = createAction(this.props.action)));
40886
41802
  }
40887
- }
41803
+ get isVisible() {
41804
+ return this.actionButton.isVisible(this.env);
41805
+ }
41806
+ get isEnabled() {
41807
+ return this.actionButton.isEnabled(this.env);
41808
+ }
41809
+ get isActive() {
41810
+ var _a, _b;
41811
+ return (_b = (_a = this.actionButton).isActive) === null || _b === void 0 ? void 0 : _b.call(_a, this.env);
41812
+ }
41813
+ get title() {
41814
+ const name = this.actionButton.name(this.env);
41815
+ const description = this.actionButton.description;
41816
+ return name + (description ? ` (${description})` : "");
41817
+ }
41818
+ get iconTitle() {
41819
+ return this.actionButton.icon;
41820
+ }
41821
+ onClick(ev) {
41822
+ var _a, _b, _c, _d;
41823
+ if (this.isEnabled) {
41824
+ (_b = (_a = this.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, ev);
41825
+ (_d = (_c = this.actionButton).execute) === null || _d === void 0 ? void 0 : _d.call(_c, this.env);
41826
+ }
41827
+ }
41828
+ get buttonStyle() {
41829
+ if (this.props.selectedColor) {
41830
+ return cssPropertiesToCss({
41831
+ "border-bottom": `4px solid ${this.props.selectedColor}`,
41832
+ height: "16px",
41833
+ "margin-top": "2px",
41834
+ });
41835
+ }
41836
+ return "";
41837
+ }
41838
+ }
41839
+ ActionButton.template = "o-spreadsheet-ActionButton";
40888
41840
 
40889
41841
  const COMPOSER_MAX_HEIGHT = 100;
40890
41842
  css /* scss */ `
@@ -40946,6 +41898,14 @@ css /* scss */ `
40946
41898
  input::-webkit-inner-spin-button {
40947
41899
  -webkit-appearance: none;
40948
41900
  }
41901
+
41902
+ .o-text-options > div {
41903
+ line-height: 26px;
41904
+ padding: 3px 12px;
41905
+ &:hover {
41906
+ background-color: rgba(0, 0, 0, 0.08);
41907
+ }
41908
+ }
40949
41909
  }
40950
41910
  `;
40951
41911
  class FontSizeEditor extends Component {
@@ -41014,41 +41974,6 @@ FontSizeEditor.props = {
41014
41974
  dropdownStyle: String,
41015
41975
  };
41016
41976
 
41017
- const FORMATS = [
41018
- { name: "automatic", text: NumberFormatTerms.Automatic },
41019
- { name: "number", text: NumberFormatTerms.Number, description: "1,000.12", value: "#,##0.00" },
41020
- { name: "percent", text: NumberFormatTerms.Percent, description: "10.12%", value: "0.00%" },
41021
- {
41022
- name: "currency",
41023
- text: NumberFormatTerms.Currency,
41024
- description: "$1,000.12",
41025
- value: "[$$]#,##0.00",
41026
- },
41027
- {
41028
- name: "currency_rounded",
41029
- text: NumberFormatTerms.CurrencyRounded,
41030
- description: "$1,000",
41031
- value: "[$$]#,##0",
41032
- },
41033
- { name: "date", text: NumberFormatTerms.Date, description: "9/26/2008", value: "m/d/yyyy" },
41034
- { name: "time", text: NumberFormatTerms.Time, description: "10:43:00 PM", value: "hh:mm:ss a" },
41035
- {
41036
- name: "datetime",
41037
- text: NumberFormatTerms.DateTime,
41038
- description: "9/26/2008 22:43:00",
41039
- value: "m/d/yyyy hh:mm:ss",
41040
- },
41041
- {
41042
- name: "duration",
41043
- text: NumberFormatTerms.Duration,
41044
- description: "27:51:38",
41045
- value: "hhhh:mm:ss",
41046
- },
41047
- ];
41048
- const CUSTOM_FORMATS = [
41049
- { name: "custom_currency", text: NumberFormatTerms.CustomCurrency, sidePanel: "CustomCurrency" },
41050
- ];
41051
- const ICONS_COLOR = "#4A4F59";
41052
41977
  // If we ever change these colors, make sure the filter tool stays green to match the icon in the grid
41053
41978
  const ACTIVE_BG_COLOR = BACKGROUND_HEADER_FILTER_COLOR;
41054
41979
  const ACTIVE_FONT_COLOR = FILTERS_COLOR;
@@ -41113,23 +42038,10 @@ css /* scss */ `
41113
42038
 
41114
42039
  /* Toolbar */
41115
42040
  .o-toolbar-tools {
41116
- .o-tool {
41117
- display: flex;
41118
- justify-content: center;
41119
- align-items: center;
41120
- margin: 2px;
41121
- padding: 0px 3px;
41122
- border-radius: 2px;
41123
- min-width: 20px;
41124
- }
41125
-
41126
- .o-filter-tool {
41127
- margin-right: 8px;
41128
- }
41129
-
41130
- .o-border-dropdown {
41131
- padding: 4px;
41132
- }
42041
+ display: flex;
42042
+ flex-shrink: 0;
42043
+ margin: 0px 6px 0px 16px;
42044
+ cursor: default;
41133
42045
 
41134
42046
  .o-divider {
41135
42047
  display: inline-block;
@@ -41138,69 +42050,33 @@ css /* scss */ `
41138
42050
  margin: 0 6px;
41139
42051
  }
41140
42052
 
41141
- .o-disabled {
41142
- opacity: 0.6;
41143
- cursor: default;
41144
- }
41145
-
41146
42053
  .o-dropdown {
41147
42054
  position: relative;
41148
42055
  display: flex;
41149
42056
  align-items: center;
41150
42057
 
41151
- .o-dropdown-button {
42058
+ > span {
41152
42059
  height: 30px;
41153
42060
  }
41154
42061
 
41155
- .o-text-options > div {
41156
- line-height: 26px;
41157
- padding: 3px 12px;
41158
- &:hover {
41159
- background-color: rgba(0, 0, 0, 0.08);
41160
- }
41161
- }
41162
-
41163
42062
  .o-dropdown-content {
41164
42063
  position: absolute;
41165
42064
  top: 100%;
41166
42065
  left: 0;
41167
42066
  overflow-y: auto;
41168
42067
  overflow-x: hidden;
42068
+ padding: 2px;
41169
42069
  z-index: ${ComponentsImportance.Dropdown};
41170
42070
  box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
41171
42071
  background-color: white;
41172
42072
 
41173
42073
  .o-dropdown-line {
41174
42074
  display: flex;
41175
- margin: 1px;
41176
42075
 
41177
- .o-line-item {
42076
+ > span {
41178
42077
  padding: 4px;
41179
- width: 18px;
41180
- height: 18px;
41181
42078
  }
41182
42079
  }
41183
-
41184
- &.o-format-tool {
41185
- padding: 5px 0;
41186
- width: 250px;
41187
- font-size: 12px;
41188
- > div {
41189
- padding: 0 20px;
41190
- white-space: nowrap;
41191
-
41192
- &.o-dropdown-active:before {
41193
- content: "✓";
41194
- font-weight: bold;
41195
- position: absolute;
41196
- left: 5px;
41197
- }
41198
- }
41199
- }
41200
-
41201
- .o-dropdown-align-item {
41202
- padding: 7px 10px;
41203
- }
41204
42080
  }
41205
42081
  }
41206
42082
  }
@@ -41210,24 +42086,20 @@ css /* scss */ `
41210
42086
  class TopBar extends Component {
41211
42087
  constructor() {
41212
42088
  super(...arguments);
41213
- this.commonFormats = FORMATS;
41214
- this.customFormats = CUSTOM_FORMATS;
41215
- this.currentFormatName = "automatic";
41216
- this.style = {};
41217
42089
  this.state = useState({
41218
42090
  menuState: { isOpen: false, position: null, menuItems: [] },
41219
42091
  activeTool: "",
42092
+ fillColor: "#ffffff",
42093
+ textColor: "#000000",
41220
42094
  });
41221
42095
  this.isSelectingMenu = false;
41222
42096
  this.openedEl = null;
41223
- this.inMerge = false;
41224
- this.cannotMerge = false;
41225
- this.undoTool = false;
41226
- this.redoTool = false;
41227
- this.paintFormatTool = false;
41228
- this.fillColor = "#ffffff";
41229
- this.textColor = "#000000";
41230
42097
  this.menus = [];
42098
+ this.EDIT = ACTION_EDIT;
42099
+ this.FORMAT = ACTION_FORMAT;
42100
+ this.VIEW = ACTION_VIEW;
42101
+ this.formatNumberMenuItemSpec = formatNumberMenuItemSpec;
42102
+ this.isntToolbarMenu = false;
41231
42103
  }
41232
42104
  get dropdownStyle() {
41233
42105
  return `max-height:${this.props.dropdownMaxHeight}px`;
@@ -41257,28 +42129,8 @@ class TopBar extends Component {
41257
42129
  this.props.onClick();
41258
42130
  this.closeMenus();
41259
42131
  }
41260
- toggleStyle(style) {
41261
- setStyle(this.env, { [style]: !this.style[style] });
41262
- }
41263
- toggleFormat(formatName) {
41264
- const formatter = FORMATS.find((f) => f.name === formatName);
41265
- const value = (formatter && formatter.value) || "";
41266
- setFormatter(this.env, value);
41267
- }
41268
- toggleHorizontalAlign(align) {
41269
- setStyle(this.env, { align });
41270
- this.onClick();
41271
- }
41272
- toggleVerticalAlign(verticalAlign) {
41273
- setStyle(this.env, { verticalAlign });
41274
- this.onClick();
41275
- }
41276
- toggleTextWrapping(wrapping) {
41277
- setStyle(this.env, { wrapping });
41278
- this.onClick();
41279
- }
41280
42132
  onMenuMouseOver(menu, ev) {
41281
- if (this.isSelectingMenu) {
42133
+ if (this.isSelectingMenu && this.isntToolbarMenu) {
41282
42134
  this.openMenu(menu, ev);
41283
42135
  }
41284
42136
  }
@@ -41289,15 +42141,27 @@ class TopBar extends Component {
41289
42141
  this.openedEl = isOpen ? null : ev.target;
41290
42142
  }
41291
42143
  toggleContextMenu(menu, ev) {
41292
- if (this.state.menuState.isOpen) {
42144
+ if (this.state.menuState.isOpen && this.isntToolbarMenu) {
42145
+ this.closeMenus();
42146
+ }
42147
+ else {
42148
+ this.openMenu(menu, ev);
42149
+ this.isntToolbarMenu = true;
42150
+ }
42151
+ }
42152
+ toggleToolbarContextMenu(menuSpec, ev) {
42153
+ if (this.state.menuState.isOpen && !this.isntToolbarMenu) {
41293
42154
  this.closeMenus();
41294
42155
  }
41295
42156
  else {
42157
+ const menu = createAction(menuSpec);
41296
42158
  this.openMenu(menu, ev);
42159
+ this.isntToolbarMenu = false;
41297
42160
  }
41298
42161
  }
41299
42162
  openMenu(menu, ev) {
41300
- const { left, top, height } = ev.target.getBoundingClientRect();
42163
+ const { left, top, height } = ev.currentTarget.getBoundingClientRect();
42164
+ this.state.activeTool = "";
41301
42165
  this.state.menuState.isOpen = true;
41302
42166
  this.state.menuState.position = { x: left, y: top + height };
41303
42167
  this.state.menuState.menuItems = menu.children(this.env);
@@ -41314,134 +42178,28 @@ class TopBar extends Component {
41314
42178
  this.openedEl = null;
41315
42179
  }
41316
42180
  updateCellState() {
41317
- const zones = this.env.model.getters.getSelectedZones();
41318
- const { col, row, sheetId } = this.env.model.getters.getActivePosition();
41319
- this.inMerge = false;
41320
- const { top, left, right, bottom } = this.env.model.getters.getSelectedZone();
41321
- const { xSplit, ySplit } = this.env.model.getters.getPaneDivisions(sheetId);
41322
- this.cannotMerge =
41323
- zones.length > 1 ||
41324
- (top === bottom && left === right) ||
41325
- (left < xSplit && xSplit <= right) ||
41326
- (top < ySplit && ySplit <= bottom);
41327
- if (!this.cannotMerge) {
41328
- const zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
41329
- this.inMerge = isEqual(zones[0], zone);
41330
- }
41331
- this.undoTool = this.env.model.getters.canUndo();
41332
- this.redoTool = this.env.model.getters.canRedo();
41333
- this.paintFormatTool = this.env.model.getters.isPaintingFormat();
41334
- const cell = this.env.model.getters.getActiveCell();
41335
- if (cell.format) {
41336
- const currentFormat = this.commonFormats.find((f) => f.value === cell.format);
41337
- this.currentFormatName = currentFormat ? currentFormat.name : "";
41338
- }
41339
- else {
41340
- this.currentFormatName = "automatic";
41341
- }
41342
- this.style = { ...this.env.model.getters.getCurrentStyle() };
41343
- this.style.align = this.style.align || cell.defaultAlign;
41344
- this.fillColor = this.style.fillColor || "#ffffff";
41345
- this.textColor = this.style.textColor || "#000000";
42181
+ const style = this.env.model.getters.getCurrentStyle();
42182
+ this.state.fillColor = style.fillColor || "#ffffff";
42183
+ this.state.textColor = style.textColor || "#000000";
41346
42184
  this.menus = topbarMenuRegistry.getMenuItems();
41347
42185
  }
41348
42186
  getMenuName(menu) {
41349
42187
  return menu.name(this.env);
41350
42188
  }
41351
- toggleMerge() {
41352
- if (this.cannotMerge) {
41353
- return;
41354
- }
41355
- const zones = this.env.model.getters.getSelectedZones();
41356
- const target = [zones[zones.length - 1]];
41357
- const sheetId = this.env.model.getters.getActiveSheetId();
41358
- if (this.inMerge) {
41359
- this.env.model.dispatch("REMOVE_MERGE", { sheetId, target });
41360
- }
41361
- else {
41362
- interactiveAddMerge(this.env, sheetId, target);
41363
- }
41364
- }
41365
42189
  setColor(target, color) {
41366
42190
  setStyle(this.env, { [target]: color });
41367
42191
  this.onClick();
41368
42192
  }
41369
- setBorder(command) {
41370
- this.env.model.dispatch("SET_FORMATTING", {
41371
- sheetId: this.env.model.getters.getActiveSheetId(),
41372
- target: this.env.model.getters.getSelectedZones(),
41373
- border: command,
41374
- });
41375
- this.onClick();
41376
- }
41377
- setFormat(format, custom) {
41378
- if (!custom) {
41379
- this.toggleFormat(format);
41380
- }
41381
- else {
41382
- this.openCustomFormatSidePanel(format);
41383
- }
41384
- this.onClick();
41385
- }
41386
- openCustomFormatSidePanel(custom) {
41387
- const customFormatter = CUSTOM_FORMATS.find((c) => c.name === custom);
41388
- const sidePanel = (customFormatter && customFormatter.sidePanel) || "";
41389
- this.env.openSidePanel(sidePanel);
41390
- }
41391
- setDecimal(step) {
41392
- this.env.model.dispatch("SET_DECIMAL", {
41393
- sheetId: this.env.model.getters.getActiveSheetId(),
41394
- target: this.env.model.getters.getSelectedZones(),
41395
- step: step,
41396
- });
41397
- }
41398
- paintFormat() {
41399
- this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", {
41400
- target: this.env.model.getters.getSelectedZones(),
41401
- });
41402
- }
41403
- clearFormatting() {
41404
- this.env.model.dispatch("CLEAR_FORMATTING", {
41405
- sheetId: this.env.model.getters.getActiveSheetId(),
41406
- target: this.env.model.getters.getSelectedZones(),
41407
- });
41408
- }
41409
- doAction(action) {
41410
- action(this.env);
41411
- this.closeMenus();
41412
- }
41413
- undo() {
41414
- this.env.model.dispatch("REQUEST_UNDO");
41415
- }
41416
- redo() {
41417
- this.env.model.dispatch("REQUEST_REDO");
41418
- }
41419
- get selectionContainsFilter() {
41420
- const sheetId = this.env.model.getters.getActiveSheetId();
41421
- const selectedZones = this.env.model.getters.getSelectedZones();
41422
- return this.env.model.getters.doesZonesContainFilter(sheetId, selectedZones);
41423
- }
41424
- get cannotCreateFilter() {
41425
- return !areZonesContinuous(...this.env.model.getters.getSelectedZones());
41426
- }
41427
- createFilter() {
41428
- if (this.cannotCreateFilter) {
41429
- return;
41430
- }
41431
- this.env.model.selection.selectTableAroundSelection();
41432
- const sheetId = this.env.model.getters.getActiveSheetId();
41433
- const selection = this.env.model.getters.getSelectedZones();
41434
- interactiveAddFilter(this.env, sheetId, selection);
41435
- }
41436
- removeFilter() {
41437
- this.env.model.dispatch("REMOVE_FILTER_TABLE", {
41438
- sheetId: this.env.model.getters.getActiveSheetId(),
41439
- target: this.env.model.getters.getSelectedZones(),
41440
- });
41441
- }
41442
42193
  }
41443
42194
  TopBar.template = "o-spreadsheet-TopBar";
41444
- TopBar.components = { ColorPickerWidget, Menu, TopBarComposer, FontSizeEditor };
42195
+ TopBar.components = {
42196
+ ColorPickerWidget,
42197
+ ColorPicker,
42198
+ Menu,
42199
+ TopBarComposer,
42200
+ FontSizeEditor,
42201
+ ActionButton,
42202
+ };
41445
42203
  TopBar.props = {
41446
42204
  onClick: Function,
41447
42205
  focusComposer: String,
@@ -41517,10 +42275,12 @@ css /* scss */ `
41517
42275
  button {
41518
42276
  color: #333;
41519
42277
  }
41520
-
41521
- * {
41522
- font-family: "Roboto", "RobotoDraft", Helvetica, Arial, sans-serif;
42278
+ .o-disabled {
42279
+ opacity: 0.4;
42280
+ pointer: default;
42281
+ pointer-events: none;
41523
42282
  }
42283
+
41524
42284
  &,
41525
42285
  *,
41526
42286
  *:before,
@@ -41549,6 +42309,10 @@ css /* scss */ `
41549
42309
  height: ${CF_ICON_EDGE_LENGTH}px;
41550
42310
  vertical-align: sub;
41551
42311
  }
42312
+
42313
+ .o-text-icon {
42314
+ vertical-align: middle;
42315
+ }
41552
42316
  `;
41553
42317
  // -----------------------------------------------------------------------------
41554
42318
  // GRID STYLE
@@ -44889,6 +45653,13 @@ class Model extends EventBus {
44889
45653
  * Internal status of the model. Important for command handling coordination
44890
45654
  */
44891
45655
  this.status = 0 /* Status.Ready */;
45656
+ /**
45657
+ * Check if a command can be dispatched, and returns a DispatchResult object with the possible
45658
+ * reasons the dispatch failed.
45659
+ */
45660
+ this.canDispatch = (type, payload) => {
45661
+ return this.checkDispatchAllowed({ ...payload, type });
45662
+ };
44892
45663
  /**
44893
45664
  * The dispatch method is the only entry point to manipulate data in the model.
44894
45665
  * This is through this method that commands are dispatched most of the time
@@ -45032,7 +45803,10 @@ class Model extends EventBus {
45032
45803
  markRaw(this);
45033
45804
  }
45034
45805
  get handlers() {
45035
- return [this.range, ...this.corePlugins, ...this.allUIPlugins, this.history];
45806
+ return [...this.coreHandlers, ...this.allUIPlugins, this.history];
45807
+ }
45808
+ get coreHandlers() {
45809
+ return [this.range, ...this.corePlugins];
45036
45810
  }
45037
45811
  get allUIPlugins() {
45038
45812
  return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
@@ -45160,6 +45934,16 @@ class Model extends EventBus {
45160
45934
  * Check if the given command is allowed by all the plugins and the history.
45161
45935
  */
45162
45936
  checkDispatchAllowed(command) {
45937
+ if (isCoreCommand(command)) {
45938
+ return this.checkDispatchAllowedCoreCommand(command);
45939
+ }
45940
+ return this.checkDispatchAllowedLocalCommand(command);
45941
+ }
45942
+ checkDispatchAllowedCoreCommand(command) {
45943
+ const results = this.coreHandlers.map((handler) => handler.allowDispatch(command));
45944
+ return new DispatchResult(results.flat());
45945
+ }
45946
+ checkDispatchAllowedLocalCommand(command) {
45163
45947
  const results = this.handlers.map((handler) => handler.allowDispatch(command));
45164
45948
  return new DispatchResult(results.flat());
45165
45949
  }
@@ -45300,6 +46084,7 @@ const registries = {
45300
46084
  inverseCommandRegistry,
45301
46085
  urlRegistry,
45302
46086
  cellPopoverRegistry,
46087
+ numberFormatMenuRegistry,
45303
46088
  };
45304
46089
  const helpers = {
45305
46090
  arg,
@@ -45357,9 +46142,9 @@ function addFunction(functionName, functionDescription) {
45357
46142
  functionRegistry.add(functionName, functionDescription);
45358
46143
  }
45359
46144
 
45360
- 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 };
46145
+ 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, setDefaultSheetViewSize, setTranslationMethod, tokenize };
45361
46146
 
45362
46147
 
45363
- __info__.version = '16.3.0-alpha.2';
45364
- __info__.date = '2023-03-23T11:36:58.645Z';
45365
- __info__.hash = '59f25bb';
46148
+ __info__.version = '16.3.0-alpha.4';
46149
+ __info__.date = '2023-04-14T12:49:16.671Z';
46150
+ __info__.hash = '6824b8a';