handsontable 15.1.0 → 15.2.0-next-9a1a15b-20250314

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.
Files changed (163) hide show
  1. package/3rdparty/walkontable/src/selection/border/border.js +16 -3
  2. package/3rdparty/walkontable/src/selection/border/border.mjs +17 -4
  3. package/3rdparty/walkontable/src/selection/scanner.js +1 -1
  4. package/3rdparty/walkontable/src/selection/scanner.mjs +2 -2
  5. package/3rdparty/walkontable/src/table.js +3 -2
  6. package/3rdparty/walkontable/src/table.mjs +4 -3
  7. package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.js +1 -0
  8. package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.mjs +1 -0
  9. package/3rdparty/walkontable/src/viewport.js +30 -3
  10. package/3rdparty/walkontable/src/viewport.mjs +30 -3
  11. package/CHANGELOG.md +40 -0
  12. package/base.js +2 -2
  13. package/base.mjs +2 -2
  14. package/core.js +2 -37
  15. package/core.mjs +2 -37
  16. package/dataMap/dataMap.js +4 -12
  17. package/dataMap/dataMap.mjs +4 -12
  18. package/dataMap/dataSource.js +2 -2
  19. package/dataMap/dataSource.mjs +2 -2
  20. package/dataMap/metaManager/metaSchema.js +2 -2
  21. package/dataMap/metaManager/metaSchema.mjs +2 -2
  22. package/dist/handsontable.css +2 -2
  23. package/dist/handsontable.full.css +2 -2
  24. package/dist/handsontable.full.js +500 -412
  25. package/dist/handsontable.full.min.css +2 -2
  26. package/dist/handsontable.full.min.js +73 -73
  27. package/dist/handsontable.js +500 -412
  28. package/dist/handsontable.min.css +2 -2
  29. package/dist/handsontable.min.js +43 -43
  30. package/dist/languages/all.js +139 -28
  31. package/dist/languages/all.min.js +1 -1
  32. package/dist/languages/fa-IR.js +167 -0
  33. package/dist/languages/fa-IR.min.js +1 -0
  34. package/dist/languages/it-IT.js +3 -0
  35. package/dist/languages/it-IT.min.js +1 -1
  36. package/dist/languages/sr-SP.js +3 -0
  37. package/dist/languages/sr-SP.min.js +1 -1
  38. package/editors/autocompleteEditor/autocompleteEditor.js +25 -20
  39. package/editors/autocompleteEditor/autocompleteEditor.mjs +25 -20
  40. package/editors/dateEditor/dateEditor.d.ts +0 -2
  41. package/editors/dateEditor/dateEditor.js +18 -7
  42. package/editors/dateEditor/dateEditor.mjs +17 -6
  43. package/editors/textEditor/textEditor.js +1 -1
  44. package/editors/textEditor/textEditor.mjs +2 -2
  45. package/focusManager.js +5 -3
  46. package/focusManager.mjs +6 -4
  47. package/helpers/dom/element.d.ts +1 -0
  48. package/helpers/dom/element.js +23 -4
  49. package/helpers/dom/element.mjs +21 -3
  50. package/helpers/dom/event.js +2 -1
  51. package/helpers/dom/event.mjs +2 -1
  52. package/helpers/mixed.js +2 -2
  53. package/helpers/mixed.mjs +2 -2
  54. package/helpers/number.js +1 -0
  55. package/helpers/number.mjs +1 -0
  56. package/i18n/languages/fa-IR.d.ts +5 -0
  57. package/i18n/languages/fa-IR.js +96 -0
  58. package/i18n/languages/fa-IR.mjs +90 -0
  59. package/i18n/languages/index.d.ts +2 -0
  60. package/i18n/languages/index.js +2 -0
  61. package/i18n/languages/index.mjs +2 -1
  62. package/i18n/languages/it-IT.js +3 -0
  63. package/i18n/languages/it-IT.mjs +3 -0
  64. package/i18n/languages/sr-SP.js +3 -0
  65. package/i18n/languages/sr-SP.mjs +3 -0
  66. package/i18n/phraseFormatters/substituteVariables.js +1 -0
  67. package/i18n/phraseFormatters/substituteVariables.mjs +1 -0
  68. package/languages/all.js +139 -28
  69. package/languages/fa-IR.js +167 -0
  70. package/languages/fa-IR.mjs +92 -0
  71. package/languages/index.js +139 -28
  72. package/languages/index.mjs +2 -1
  73. package/languages/it-IT.js +3 -0
  74. package/languages/it-IT.mjs +3 -0
  75. package/languages/sr-SP.js +3 -0
  76. package/languages/sr-SP.mjs +3 -0
  77. package/package.json +13 -2
  78. package/plugins/columnSorting/columnSorting.js +17 -1
  79. package/plugins/columnSorting/columnSorting.mjs +18 -2
  80. package/plugins/columnSorting/columnStatesManager.js +1 -0
  81. package/plugins/columnSorting/columnStatesManager.mjs +1 -0
  82. package/plugins/columnSorting/utils.js +14 -0
  83. package/plugins/columnSorting/utils.mjs +13 -0
  84. package/plugins/comments/comments.js +5 -2
  85. package/plugins/comments/comments.mjs +6 -3
  86. package/plugins/contextMenu/menu/menu.js +9 -3
  87. package/plugins/contextMenu/menu/menu.mjs +9 -3
  88. package/plugins/contextMenu/predefinedItems/columnLeft.js +3 -8
  89. package/plugins/contextMenu/predefinedItems/columnLeft.mjs +3 -8
  90. package/plugins/contextMenu/predefinedItems/columnRight.js +2 -9
  91. package/plugins/contextMenu/predefinedItems/columnRight.mjs +2 -9
  92. package/plugins/contextMenu/predefinedItems/rowAbove.js +3 -8
  93. package/plugins/contextMenu/predefinedItems/rowAbove.mjs +3 -8
  94. package/plugins/contextMenu/predefinedItems/rowBelow.js +2 -9
  95. package/plugins/contextMenu/predefinedItems/rowBelow.mjs +2 -9
  96. package/plugins/copyPaste/copyPaste.js +6 -12
  97. package/plugins/copyPaste/copyPaste.mjs +7 -13
  98. package/plugins/exportFile/types/csv.js +1 -0
  99. package/plugins/exportFile/types/csv.mjs +1 -0
  100. package/plugins/filters/conditionCollection.js +0 -26
  101. package/plugins/filters/conditionCollection.mjs +0 -26
  102. package/plugins/filters/filters.d.ts +2 -0
  103. package/plugins/filters/filters.js +77 -8
  104. package/plugins/filters/filters.mjs +77 -8
  105. package/plugins/mergeCells/mergeCells.js +9 -6
  106. package/plugins/mergeCells/mergeCells.mjs +9 -6
  107. package/plugins/multiColumnSorting/multiColumnSorting.js +1 -21
  108. package/plugins/multiColumnSorting/multiColumnSorting.mjs +1 -21
  109. package/plugins/nestedHeaders/nestedHeaders.js +5 -3
  110. package/plugins/nestedHeaders/nestedHeaders.mjs +5 -3
  111. package/plugins/nestedHeaders/stateManager/index.js +1 -0
  112. package/plugins/nestedHeaders/stateManager/index.mjs +1 -0
  113. package/plugins/undoRedo/actions/_base.js +10 -0
  114. package/plugins/undoRedo/actions/_base.mjs +10 -0
  115. package/plugins/undoRedo/actions/cellAlignment.js +1 -1
  116. package/plugins/undoRedo/actions/cellAlignment.mjs +1 -1
  117. package/plugins/undoRedo/actions/columnMove.js +1 -1
  118. package/plugins/undoRedo/actions/columnMove.mjs +1 -1
  119. package/plugins/undoRedo/actions/columnSort.js +1 -1
  120. package/plugins/undoRedo/actions/columnSort.mjs +1 -1
  121. package/plugins/undoRedo/actions/createColumn.js +1 -1
  122. package/plugins/undoRedo/actions/createColumn.mjs +1 -1
  123. package/plugins/undoRedo/actions/createRow.js +1 -1
  124. package/plugins/undoRedo/actions/createRow.mjs +1 -1
  125. package/plugins/undoRedo/actions/dataChange.js +1 -1
  126. package/plugins/undoRedo/actions/dataChange.mjs +1 -1
  127. package/plugins/undoRedo/actions/filters.js +3 -3
  128. package/plugins/undoRedo/actions/filters.mjs +3 -3
  129. package/plugins/undoRedo/actions/mergeCells.js +4 -1
  130. package/plugins/undoRedo/actions/mergeCells.mjs +4 -1
  131. package/plugins/undoRedo/actions/removeColumn.js +4 -2
  132. package/plugins/undoRedo/actions/removeColumn.mjs +4 -2
  133. package/plugins/undoRedo/actions/removeRow.js +1 -1
  134. package/plugins/undoRedo/actions/removeRow.mjs +1 -1
  135. package/plugins/undoRedo/actions/rowMove.js +1 -1
  136. package/plugins/undoRedo/actions/rowMove.mjs +1 -1
  137. package/plugins/undoRedo/actions/unmergeCells.js +4 -1
  138. package/plugins/undoRedo/actions/unmergeCells.mjs +4 -1
  139. package/plugins/undoRedo/undoRedo.d.ts +48 -17
  140. package/renderers/checkboxRenderer/checkboxRenderer.js +1 -1
  141. package/renderers/checkboxRenderer/checkboxRenderer.mjs +2 -2
  142. package/renderers/numericRenderer/numericRenderer.js +10 -2
  143. package/renderers/numericRenderer/numericRenderer.mjs +10 -2
  144. package/renderers/textRenderer/textRenderer.js +3 -12
  145. package/renderers/textRenderer/textRenderer.mjs +4 -13
  146. package/shortcuts/utils.js +1 -0
  147. package/shortcuts/utils.mjs +1 -0
  148. package/styles/handsontable.css +83 -99
  149. package/styles/handsontable.min.css +3 -3
  150. package/styles/ht-theme-horizon.css +14 -2
  151. package/styles/ht-theme-horizon.min.css +3 -3
  152. package/styles/ht-theme-main.css +14 -2
  153. package/styles/ht-theme-main.min.css +3 -3
  154. package/tableView.js +9 -0
  155. package/tableView.mjs +9 -0
  156. package/translations/maps/linkedPhysicalIndexToValueMap.js +1 -0
  157. package/translations/maps/linkedPhysicalIndexToValueMap.mjs +1 -0
  158. package/translations/maps/utils/physicallyIndexed.js +1 -0
  159. package/translations/maps/utils/physicallyIndexed.mjs +1 -0
  160. package/utils/dataStructures/priorityMap.js +1 -0
  161. package/utils/dataStructures/priorityMap.mjs +1 -0
  162. package/plugins/multiColumnSorting/utils.js +0 -13
  163. package/plugins/multiColumnSorting/utils.mjs +0 -9
@@ -191,8 +191,14 @@ class Border {
191
191
  */
192
192
  createMultipleSelectorHandles() {
193
193
  const {
194
- rootDocument
194
+ rootDocument,
195
+ stylesHandler
195
196
  } = this.wot;
197
+ const cellMobileHandleSize = stylesHandler.getCSSVariableValue('cell-mobile-handle-size');
198
+ const cellMobileHandleBorderRadius = stylesHandler.getCSSVariableValue('cell-mobile-handle-border-radius');
199
+ const cellMobileHandleBackgroundColor = stylesHandler.getCSSVariableValue('cell-mobile-handle-background-color');
200
+ const cellMobileHandleBorderWidth = stylesHandler.getCSSVariableValue('cell-mobile-handle-border-width');
201
+ const cellMobileHandleBorderColor = stylesHandler.getCSSVariableValue('cell-mobile-handle-border-color');
196
202
  this.selectionHandles = {
197
203
  top: rootDocument.createElement('DIV'),
198
204
  topHitArea: rootDocument.createElement('DIV'),
@@ -221,13 +227,20 @@ class Border {
221
227
  this.selectionHandles.styles.bottomHitArea[key] = value;
222
228
  this.selectionHandles.styles.topHitArea[key] = value;
223
229
  });
224
- const handleStyle = {
230
+ const handleStyle = stylesHandler.isClassicTheme() ? {
225
231
  position: 'absolute',
226
232
  height: `${width}px`,
227
233
  width: `${width}px`,
228
234
  'border-radius': `${parseInt(width / 1.5, 10)}px`,
229
235
  background: '#F5F5FF',
230
236
  border: '1px solid #4285c8'
237
+ } : {
238
+ position: 'absolute',
239
+ height: `${cellMobileHandleSize}px`,
240
+ width: `${cellMobileHandleSize}px`,
241
+ 'border-radius': `${cellMobileHandleBorderRadius}px`,
242
+ background: `${cellMobileHandleBackgroundColor}`,
243
+ border: `${cellMobileHandleBorderWidth}px solid ${cellMobileHandleBorderColor}`
231
244
  };
232
245
  (0, _object.objectEach)(handleStyle, (value, key) => {
233
246
  this.selectionHandles.styles.bottom[key] = value;
@@ -352,7 +365,7 @@ class Border {
352
365
  fromTD = wtTable.getCell(this.wot.createCellCoords(fromRow, fromColumn));
353
366
  } else {
354
367
  fromTD = wtTable.getCell(this.wot.createCellCoords(fromRow, fromColumn));
355
- if (!(fromTD instanceof HTMLElement)) {
368
+ if (!(0, _element.isHTMLElement)(fromTD)) {
356
369
  this.disappear();
357
370
  return;
358
371
  }
@@ -1,4 +1,4 @@
1
- import { addClass, hasClass, removeClass, getTrimmingContainer, innerWidth, innerHeight, offset, outerHeight, outerWidth } from "../../../../../helpers/dom/element.mjs";
1
+ import { addClass, hasClass, removeClass, getTrimmingContainer, innerWidth, innerHeight, offset, outerHeight, outerWidth, isHTMLElement } from "../../../../../helpers/dom/element.mjs";
2
2
  import { stopImmediatePropagation } from "../../../../../helpers/dom/event.mjs";
3
3
  import { objectEach } from "../../../../../helpers/object.mjs";
4
4
  import { isMobileBrowser } from "../../../../../helpers/browser.mjs";
@@ -188,8 +188,14 @@ class Border {
188
188
  */
189
189
  createMultipleSelectorHandles() {
190
190
  const {
191
- rootDocument
191
+ rootDocument,
192
+ stylesHandler
192
193
  } = this.wot;
194
+ const cellMobileHandleSize = stylesHandler.getCSSVariableValue('cell-mobile-handle-size');
195
+ const cellMobileHandleBorderRadius = stylesHandler.getCSSVariableValue('cell-mobile-handle-border-radius');
196
+ const cellMobileHandleBackgroundColor = stylesHandler.getCSSVariableValue('cell-mobile-handle-background-color');
197
+ const cellMobileHandleBorderWidth = stylesHandler.getCSSVariableValue('cell-mobile-handle-border-width');
198
+ const cellMobileHandleBorderColor = stylesHandler.getCSSVariableValue('cell-mobile-handle-border-color');
193
199
  this.selectionHandles = {
194
200
  top: rootDocument.createElement('DIV'),
195
201
  topHitArea: rootDocument.createElement('DIV'),
@@ -218,13 +224,20 @@ class Border {
218
224
  this.selectionHandles.styles.bottomHitArea[key] = value;
219
225
  this.selectionHandles.styles.topHitArea[key] = value;
220
226
  });
221
- const handleStyle = {
227
+ const handleStyle = stylesHandler.isClassicTheme() ? {
222
228
  position: 'absolute',
223
229
  height: `${width}px`,
224
230
  width: `${width}px`,
225
231
  'border-radius': `${parseInt(width / 1.5, 10)}px`,
226
232
  background: '#F5F5FF',
227
233
  border: '1px solid #4285c8'
234
+ } : {
235
+ position: 'absolute',
236
+ height: `${cellMobileHandleSize}px`,
237
+ width: `${cellMobileHandleSize}px`,
238
+ 'border-radius': `${cellMobileHandleBorderRadius}px`,
239
+ background: `${cellMobileHandleBackgroundColor}`,
240
+ border: `${cellMobileHandleBorderWidth}px solid ${cellMobileHandleBorderColor}`
228
241
  };
229
242
  objectEach(handleStyle, (value, key) => {
230
243
  this.selectionHandles.styles.bottom[key] = value;
@@ -349,7 +362,7 @@ class Border {
349
362
  fromTD = wtTable.getCell(this.wot.createCellCoords(fromRow, fromColumn));
350
363
  } else {
351
364
  fromTD = wtTable.getCell(this.wot.createCellCoords(fromRow, fromColumn));
352
- if (!(fromTD instanceof HTMLElement)) {
365
+ if (!isHTMLElement(fromTD)) {
353
366
  this.disappear();
354
367
  return;
355
368
  }
@@ -273,7 +273,7 @@ function _scanCellsRange(callback) {
273
273
  }
274
274
  } else {
275
275
  const cell = wtTable.getCell(_classPrivateFieldGet(_activeOverlaysWot, this).createCellCoords(topRow, startColumn));
276
- if (!(cell instanceof HTMLElement)) {
276
+ if (!(0, _element.isHTMLElement)(cell)) {
277
277
  return;
278
278
  }
279
279
  }
@@ -13,7 +13,7 @@ function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
13
13
  function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
14
14
  function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
15
15
  /* eslint-disable no-continue */
16
- import { addClass } from "../../../../helpers/dom/element.mjs";
16
+ import { addClass, isHTMLElement } from "../../../../helpers/dom/element.mjs";
17
17
  /**
18
18
  * Selection scanner module scans the rendered cells and headers and if it finds an intersection with
19
19
  * the coordinates of the Selection class (highlight) it returns the DOM elements.
@@ -270,7 +270,7 @@ function _scanCellsRange(callback) {
270
270
  }
271
271
  } else {
272
272
  const cell = wtTable.getCell(_classPrivateFieldGet(_activeOverlaysWot, this).createCellCoords(topRow, startColumn));
273
- if (!(cell instanceof HTMLElement)) {
273
+ if (!isHTMLElement(cell)) {
274
274
  return;
275
275
  }
276
276
  }
@@ -213,6 +213,7 @@ class Table {
213
213
  holder = this.domBindings.rootDocument.createElement('div');
214
214
  holder.style.position = 'relative';
215
215
  holder.className = 'wtHolder';
216
+ (0, _element.setAttribute)(holder, [(0, _a11y.A11Y_TABINDEX)(-1)]);
216
217
  if (parent) {
217
218
  // if TABLE is detached (e.g. in Jasmine test), it has no parentNode so we cannot attach holder to it
218
219
  parent.insertBefore(holder, hider);
@@ -609,12 +610,12 @@ class Table {
609
610
  row = totalRows - CONTAINER.childNodes.length + row;
610
611
  } else if (CONTAINER === this.THEAD) {
611
612
  row = this.rowFilter.visibleColHeadedRowToSourceRow(row);
612
- } else {
613
+ } else if (this.rowFilter) {
613
614
  row = this.rowFilter.renderedToSource(row);
614
615
  }
615
616
  if ((0, _element.overlayContainsElement)(_overlay.CLONE_TOP_INLINE_START_CORNER, cellElement, this.wtRootElement) || (0, _element.overlayContainsElement)(_overlay.CLONE_INLINE_START, cellElement, this.wtRootElement) || (0, _element.overlayContainsElement)(_overlay.CLONE_BOTTOM_INLINE_START_CORNER, cellElement, this.wtRootElement)) {
616
617
  col = this.columnFilter.offsettedTH(col);
617
- } else {
618
+ } else if (this.columnFilter) {
618
619
  col = this.columnFilter.visibleRowHeadedColumnToSourceColumn(col);
619
620
  }
620
621
  const hookResult = this.wtSettings.getSetting('onModifyGetCoordsElement', row, col);
@@ -13,7 +13,7 @@ import { Renderer } from "./renderer/index.mjs";
13
13
  import ColumnUtils from "./utils/column.mjs";
14
14
  import RowUtils from "./utils/row.mjs";
15
15
  import { CLONE_TOP, CLONE_BOTTOM, CLONE_INLINE_START, CLONE_TOP_INLINE_START_CORNER, CLONE_BOTTOM_INLINE_START_CORNER } from "./overlay/index.mjs";
16
- import { A11Y_PRESENTATION } from "../../../helpers/a11y.mjs";
16
+ import { A11Y_PRESENTATION, A11Y_TABINDEX } from "../../../helpers/a11y.mjs";
17
17
  /**
18
18
  * @todo These mixes are never added to the class Table, however their members are used here.
19
19
  * @todo Continue: Potentially it works only, because some of these mixes are added to every inherited class.
@@ -209,6 +209,7 @@ class Table {
209
209
  holder = this.domBindings.rootDocument.createElement('div');
210
210
  holder.style.position = 'relative';
211
211
  holder.className = 'wtHolder';
212
+ setAttribute(holder, [A11Y_TABINDEX(-1)]);
212
213
  if (parent) {
213
214
  // if TABLE is detached (e.g. in Jasmine test), it has no parentNode so we cannot attach holder to it
214
215
  parent.insertBefore(holder, hider);
@@ -605,12 +606,12 @@ class Table {
605
606
  row = totalRows - CONTAINER.childNodes.length + row;
606
607
  } else if (CONTAINER === this.THEAD) {
607
608
  row = this.rowFilter.visibleColHeadedRowToSourceRow(row);
608
- } else {
609
+ } else if (this.rowFilter) {
609
610
  row = this.rowFilter.renderedToSource(row);
610
611
  }
611
612
  if (overlayContainsElement(CLONE_TOP_INLINE_START_CORNER, cellElement, this.wtRootElement) || overlayContainsElement(CLONE_INLINE_START, cellElement, this.wtRootElement) || overlayContainsElement(CLONE_BOTTOM_INLINE_START_CORNER, cellElement, this.wtRootElement)) {
612
613
  col = this.columnFilter.offsettedTH(col);
613
- } else {
614
+ } else if (this.columnFilter) {
614
615
  col = this.columnFilter.visibleRowHeadedColumnToSourceColumn(col);
615
616
  }
616
617
  const hookResult = this.wtSettings.getSetting('onModifyGetCoordsElement', row, col);
@@ -3,6 +3,7 @@
3
3
  exports.__esModule = true;
4
4
  require("core-js/modules/es.error.cause.js");
5
5
  require("core-js/modules/es.array.unshift.js");
6
+ require("core-js/modules/esnext.iterator.constructor.js");
6
7
  require("core-js/modules/esnext.iterator.map.js");
7
8
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
8
9
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
@@ -1,5 +1,6 @@
1
1
  import "core-js/modules/es.error.cause.js";
2
2
  import "core-js/modules/es.array.unshift.js";
3
+ import "core-js/modules/esnext.iterator.constructor.js";
3
4
  import "core-js/modules/esnext.iterator.map.js";
4
5
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
6
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
+ require("core-js/modules/esnext.iterator.constructor.js");
4
5
  require("core-js/modules/esnext.iterator.map.js");
5
6
  var _element = require("../../../helpers/dom/element");
6
7
  var _object = require("../../../helpers/object");
@@ -123,7 +124,20 @@ class Viewport {
123
124
  * @returns {boolean}
124
125
  */
125
126
  hasVerticalScroll() {
126
- return this.wtTable.hider.offsetHeight > this.getWorkspaceHeight();
127
+ if (this.isVerticallyScrollableByWindow()) {
128
+ const documentElement = this.domBindings.rootDocument.documentElement;
129
+ return documentElement.scrollHeight > documentElement.clientHeight;
130
+ }
131
+ const {
132
+ holder,
133
+ hider
134
+ } = this.wtTable;
135
+ const holderHeight = holder.clientHeight;
136
+ const hiderOffsetHeight = hider.offsetHeight;
137
+ if (holderHeight < hiderOffsetHeight) {
138
+ return true;
139
+ }
140
+ return hiderOffsetHeight > this.getWorkspaceHeight();
127
141
  }
128
142
 
129
143
  /**
@@ -132,7 +146,20 @@ class Viewport {
132
146
  * @returns {boolean}
133
147
  */
134
148
  hasHorizontalScroll() {
135
- return this.wtTable.hider.offsetWidth > this.getWorkspaceWidth();
149
+ if (this.isVerticallyScrollableByWindow()) {
150
+ const documentElement = this.domBindings.rootDocument.documentElement;
151
+ return documentElement.scrollWidth > documentElement.clientWidth;
152
+ }
153
+ const {
154
+ holder,
155
+ hider
156
+ } = this.wtTable;
157
+ const holderWidth = holder.clientWidth;
158
+ const hiderOffsetWidth = hider.offsetWidth;
159
+ if (holderWidth < hiderOffsetWidth) {
160
+ return true;
161
+ }
162
+ return hiderOffsetWidth > this.getWorkspaceWidth();
136
163
  }
137
164
 
138
165
  /**
@@ -172,7 +199,7 @@ class Viewport {
172
199
  * @returns {number}
173
200
  */
174
201
  getWorkspaceOffset() {
175
- return (0, _element.offset)(this.wtTable.TABLE);
202
+ return (0, _element.offset)(this.wtTable.holder);
176
203
  }
177
204
 
178
205
  /**
@@ -1,3 +1,4 @@
1
+ import "core-js/modules/esnext.iterator.constructor.js";
1
2
  import "core-js/modules/esnext.iterator.map.js";
2
3
  import { getScrollbarWidth, offset, outerHeight, outerWidth } from "../../../helpers/dom/element.mjs";
3
4
  import { objectEach } from "../../../helpers/object.mjs";
@@ -120,7 +121,20 @@ class Viewport {
120
121
  * @returns {boolean}
121
122
  */
122
123
  hasVerticalScroll() {
123
- return this.wtTable.hider.offsetHeight > this.getWorkspaceHeight();
124
+ if (this.isVerticallyScrollableByWindow()) {
125
+ const documentElement = this.domBindings.rootDocument.documentElement;
126
+ return documentElement.scrollHeight > documentElement.clientHeight;
127
+ }
128
+ const {
129
+ holder,
130
+ hider
131
+ } = this.wtTable;
132
+ const holderHeight = holder.clientHeight;
133
+ const hiderOffsetHeight = hider.offsetHeight;
134
+ if (holderHeight < hiderOffsetHeight) {
135
+ return true;
136
+ }
137
+ return hiderOffsetHeight > this.getWorkspaceHeight();
124
138
  }
125
139
 
126
140
  /**
@@ -129,7 +143,20 @@ class Viewport {
129
143
  * @returns {boolean}
130
144
  */
131
145
  hasHorizontalScroll() {
132
- return this.wtTable.hider.offsetWidth > this.getWorkspaceWidth();
146
+ if (this.isVerticallyScrollableByWindow()) {
147
+ const documentElement = this.domBindings.rootDocument.documentElement;
148
+ return documentElement.scrollWidth > documentElement.clientWidth;
149
+ }
150
+ const {
151
+ holder,
152
+ hider
153
+ } = this.wtTable;
154
+ const holderWidth = holder.clientWidth;
155
+ const hiderOffsetWidth = hider.offsetWidth;
156
+ if (holderWidth < hiderOffsetWidth) {
157
+ return true;
158
+ }
159
+ return hiderOffsetWidth > this.getWorkspaceWidth();
133
160
  }
134
161
 
135
162
  /**
@@ -169,7 +196,7 @@ class Viewport {
169
196
  * @returns {number}
170
197
  */
171
198
  getWorkspaceOffset() {
172
- return offset(this.wtTable.TABLE);
199
+ return offset(this.wtTable.holder);
173
200
  }
174
201
 
175
202
  /**
package/CHANGELOG.md CHANGED
@@ -9,6 +9,46 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
9
 
10
10
  <!-- UNVERSIONED -->
11
11
 
12
+ ## [15.2.0] - 2025-03-19
13
+
14
+ ### Added
15
+ - Added Farsi translations [#11388](https://github.com/handsontable/handsontable/pull/11388)
16
+ - Added support for className as an array in numeric renderer [#11420](https://github.com/handsontable/handsontable/pull/11420)
17
+ - Updated Italian translation for new context menu labels (PR-10117-fix) [#11436](https://github.com/handsontable/handsontable/pull/11436)
18
+ - Updated Serbian translation for new context menu labels (PR-10115-fix) [#11437](https://github.com/handsontable/handsontable/pull/11437)
19
+ - Added mobile cell handle css variables to the themes [#11479](https://github.com/handsontable/handsontable/pull/11479)
20
+ - Improved execution flow of the Filters plugin and added two new methods [#11488](https://github.com/handsontable/handsontable/pull/11488)
21
+
22
+ ### Changed
23
+ - Speed up the rendering performance for themes [#11443](https://github.com/handsontable/handsontable/pull/11443)
24
+ - Improved table UI behavior after removing all rows and/or columns [#11477](https://github.com/handsontable/handsontable/pull/11477)
25
+ - Revert `actionType` class field for UndoRedo actions [#11495](https://github.com/handsontable/handsontable/pull/11495)
26
+
27
+ ### Removed
28
+ - Removed broken, unsupported and undocumented `rendererTemplate` option [#11424](https://github.com/handsontable/handsontable/pull/11424)
29
+
30
+ ### Fixed
31
+ - Fixed default (fallback) date format for Date editor [#11419](https://github.com/handsontable/handsontable/pull/11419)
32
+ - Fixed context menu alter item activity [#11422](https://github.com/handsontable/handsontable/pull/11422)
33
+ - Add checkbox input visibility for the no-theme variant [#11427](https://github.com/handsontable/handsontable/pull/11427)
34
+ - Fix cell text reading when imeFastEdit is enabled [#11442](https://github.com/handsontable/handsontable/pull/11442)
35
+ - Fixed a problem, where clicking on the Comments' editor element deselected the currently selected cells. [#11446](https://github.com/handsontable/handsontable/pull/11446)
36
+ - Fixed `hasVerticalScroll` and `hasHorizontalScroll` methods [#11455](https://github.com/handsontable/handsontable/pull/11455)
37
+ - Fix editor border radius on mobile devices [#11457](https://github.com/handsontable/handsontable/pull/11457)
38
+ - Fixed the wrong height of the first row [#11458](https://github.com/handsontable/handsontable/pull/11458)
39
+ - Fix single cell selection inside iframe and new HTMLElement check [#11460](https://github.com/handsontable/handsontable/pull/11460)
40
+ - Fixed an issue with row header misalignment [#11465](https://github.com/handsontable/handsontable/pull/11465)
41
+ - Improved autocomplete/dropdown editor list behavior [#11469](https://github.com/handsontable/handsontable/pull/11469)
42
+ - Fixed problem with horizontal scroll in autocomplete dropdown [#11473](https://github.com/handsontable/handsontable/pull/11473)
43
+ - Fixed merged cells height for custom defined row heights [#11478](https://github.com/handsontable/handsontable/pull/11478)
44
+ - Fixed a problem with the Comments editor not flipping direction when overlapping the window's scrollbars. [#11481](https://github.com/handsontable/handsontable/pull/11481)
45
+ - Fixed problem with focus trap during Shift + Tab navigation [#11483](https://github.com/handsontable/handsontable/pull/11483)
46
+ - Fixed issue with context menu opening on classic theme [#11486](https://github.com/handsontable/handsontable/pull/11486)
47
+ - Fixed problem with rowHeights when the value is lower than the default/min row height [#11487](https://github.com/handsontable/handsontable/pull/11487)
48
+ - Fixed an issue with data source modification for row values as a string [#11491](https://github.com/handsontable/handsontable/pull/11491)
49
+ - Fixed conflicts between ColumnSorting and MultiColumnSorting plugins [#11492](https://github.com/handsontable/handsontable/pull/11492)
50
+ - Fixed copy, cut an paste actions on tables with a selection reaching outside of the rendered viewport. [#11504](https://github.com/handsontable/handsontable/pull/11504)
51
+
12
52
  ## [15.1.0] - 2025-02-20
13
53
 
14
54
  ### Added
package/base.js CHANGED
@@ -45,8 +45,8 @@ Handsontable.hooks = _hooks.Hooks.getSingleton();
45
45
  Handsontable.CellCoords = _src.CellCoords;
46
46
  Handsontable.CellRange = _src.CellRange;
47
47
  Handsontable.packageName = 'handsontable';
48
- Handsontable.buildDate = "19/02/2025 10:01:04";
49
- Handsontable.version = "15.1.0";
48
+ Handsontable.buildDate = "14/03/2025 11:50:09";
49
+ Handsontable.version = "15.2.0-next-9a1a15b-20250314";
50
50
  Handsontable.languages = {
51
51
  dictionaryKeys: _registry.dictionaryKeys,
52
52
  getLanguageDictionary: _registry.getLanguageDictionary,
package/base.mjs CHANGED
@@ -35,8 +35,8 @@ Handsontable.hooks = Hooks.getSingleton();
35
35
  Handsontable.CellCoords = CellCoords;
36
36
  Handsontable.CellRange = CellRange;
37
37
  Handsontable.packageName = 'handsontable';
38
- Handsontable.buildDate = "19/02/2025 10:01:07";
39
- Handsontable.version = "15.1.0";
38
+ Handsontable.buildDate = "14/03/2025 11:50:15";
39
+ Handsontable.version = "15.2.0-next-9a1a15b-20250314";
40
40
  Handsontable.languages = {
41
41
  dictionaryKeys,
42
42
  getLanguageDictionary,
package/core.js CHANGED
@@ -3556,6 +3556,7 @@ function Core(rootElement, userSettings) {
3556
3556
  * @returns {number}
3557
3557
  */
3558
3558
  this._getRowHeightFromSettings = function (row) {
3559
+ const defaultRowHeight = this.view.getDefaultRowHeight();
3559
3560
  let height = tableMeta.rowHeights;
3560
3561
  if (height !== undefined && height !== null) {
3561
3562
  switch (typeof height) {
@@ -3573,7 +3574,7 @@ function Core(rootElement, userSettings) {
3573
3574
  height = parseInt(height, 10);
3574
3575
  }
3575
3576
  }
3576
- return height;
3577
+ return height !== undefined && height !== null && height < defaultRowHeight ? defaultRowHeight : height;
3577
3578
  };
3578
3579
 
3579
3580
  /**
@@ -4688,42 +4689,6 @@ function Core(rootElement, userSettings) {
4688
4689
  this._getEditorManager = function () {
4689
4690
  return editorManager;
4690
4691
  };
4691
-
4692
- /**
4693
- * Check if currently it is RTL direction.
4694
- *
4695
- * @private
4696
- * @memberof Core#
4697
- * @function isRtl
4698
- * @returns {boolean} True if RTL.
4699
- */
4700
- this.isRtl = function () {
4701
- return instance.rootWindow.getComputedStyle(instance.rootElement).direction === 'rtl';
4702
- };
4703
-
4704
- /**
4705
- * Check if currently it is LTR direction.
4706
- *
4707
- * @private
4708
- * @memberof Core#
4709
- * @function isLtr
4710
- * @returns {boolean} True if LTR.
4711
- */
4712
- this.isLtr = function () {
4713
- return !instance.isRtl();
4714
- };
4715
-
4716
- /**
4717
- * Returns 1 for LTR; -1 for RTL. Useful for calculations.
4718
- *
4719
- * @private
4720
- * @memberof Core#
4721
- * @function getDirectionFactor
4722
- * @returns {number} Returns 1 for LTR; -1 for RTL.
4723
- */
4724
- this.getDirectionFactor = function () {
4725
- return instance.isLtr() ? 1 : -1;
4726
- };
4727
4692
  const shortcutManager = (0, _shortcuts.createShortcutManager)({
4728
4693
  handleEvent() {
4729
4694
  return instance.isListening();
package/core.mjs CHANGED
@@ -3551,6 +3551,7 @@ export default function Core(rootElement, userSettings) {
3551
3551
  * @returns {number}
3552
3552
  */
3553
3553
  this._getRowHeightFromSettings = function (row) {
3554
+ const defaultRowHeight = this.view.getDefaultRowHeight();
3554
3555
  let height = tableMeta.rowHeights;
3555
3556
  if (height !== undefined && height !== null) {
3556
3557
  switch (typeof height) {
@@ -3568,7 +3569,7 @@ export default function Core(rootElement, userSettings) {
3568
3569
  height = parseInt(height, 10);
3569
3570
  }
3570
3571
  }
3571
- return height;
3572
+ return height !== undefined && height !== null && height < defaultRowHeight ? defaultRowHeight : height;
3572
3573
  };
3573
3574
 
3574
3575
  /**
@@ -4683,42 +4684,6 @@ export default function Core(rootElement, userSettings) {
4683
4684
  this._getEditorManager = function () {
4684
4685
  return editorManager;
4685
4686
  };
4686
-
4687
- /**
4688
- * Check if currently it is RTL direction.
4689
- *
4690
- * @private
4691
- * @memberof Core#
4692
- * @function isRtl
4693
- * @returns {boolean} True if RTL.
4694
- */
4695
- this.isRtl = function () {
4696
- return instance.rootWindow.getComputedStyle(instance.rootElement).direction === 'rtl';
4697
- };
4698
-
4699
- /**
4700
- * Check if currently it is LTR direction.
4701
- *
4702
- * @private
4703
- * @memberof Core#
4704
- * @function isLtr
4705
- * @returns {boolean} True if LTR.
4706
- */
4707
- this.isLtr = function () {
4708
- return !instance.isRtl();
4709
- };
4710
-
4711
- /**
4712
- * Returns 1 for LTR; -1 for RTL. Useful for calculations.
4713
- *
4714
- * @private
4715
- * @memberof Core#
4716
- * @function getDirectionFactor
4717
- * @returns {number} Returns 1 for LTR; -1 for RTL.
4718
- */
4719
- this.getDirectionFactor = function () {
4720
- return instance.isLtr() ? 1 : -1;
4721
- };
4722
4687
  const shortcutManager = createShortcutManager({
4723
4688
  handleEvent() {
4724
4689
  return instance.isListening();
@@ -117,7 +117,7 @@ class DataMap {
117
117
  this.metaManager = metaManager;
118
118
  this.tableMeta = metaManager.getTableMeta();
119
119
  this.dataSource = data;
120
- this.duckSchema = this.createDuckSchema();
120
+ this.refreshDuckSchema();
121
121
  this.createMap();
122
122
  }
123
123
 
@@ -480,14 +480,10 @@ class DataMap {
480
480
  // List of removed indexes might be changed in the `beforeRemoveRow` hook. There may be new values.
481
481
  const numberOfRemovedIndexes = removedPhysicalIndexes.length;
482
482
  this.filterData(rowIndex, numberOfRemovedIndexes, removedPhysicalIndexes);
483
-
484
- // TODO: Function `removeRow` should validate fully, probably above.
485
483
  if (rowIndex < this.hot.countRows()) {
486
484
  this.hot.rowIndexMapper.removeIndexes(removedPhysicalIndexes);
487
- const customDefinedColumns = (0, _mixed.isDefined)(this.tableMeta.columns) || (0, _mixed.isDefined)(this.tableMeta.dataSchema);
488
-
489
- // All rows have been removed. There shouldn't be any columns.
490
- if (this.hot.rowIndexMapper.getNotTrimmedIndexesLength() === 0 && customDefinedColumns === false) {
485
+ const preserveColumns = (0, _mixed.isDefined)(this.tableMeta.columns) || (0, _mixed.isDefined)(this.tableMeta.dataSchema) || this.tableMeta.colHeaders;
486
+ if (this.hot.rowIndexMapper.getNotTrimmedIndexesLength() === 0 && !preserveColumns) {
491
487
  this.hot.columnIndexMapper.setIndexesSequence([]);
492
488
  }
493
489
  }
@@ -550,13 +546,9 @@ class DataMap {
550
546
  }
551
547
  }
552
548
  }
553
-
554
- // TODO: Function `removeCol` should validate fully, probably above.
555
549
  if (columnIndex < this.hot.countCols()) {
556
550
  this.hot.columnIndexMapper.removeIndexes(removedPhysicalIndexes);
557
-
558
- // All columns have been removed. There shouldn't be any rows.
559
- if (this.hot.columnIndexMapper.getNotTrimmedIndexesLength() === 0) {
551
+ if (!this.tableMeta.rowHeaders && this.hot.columnIndexMapper.getNotTrimmedIndexesLength() === 0) {
560
552
  this.hot.rowIndexMapper.setIndexesSequence([]);
561
553
  }
562
554
  }
@@ -113,7 +113,7 @@ class DataMap {
113
113
  this.metaManager = metaManager;
114
114
  this.tableMeta = metaManager.getTableMeta();
115
115
  this.dataSource = data;
116
- this.duckSchema = this.createDuckSchema();
116
+ this.refreshDuckSchema();
117
117
  this.createMap();
118
118
  }
119
119
 
@@ -476,14 +476,10 @@ class DataMap {
476
476
  // List of removed indexes might be changed in the `beforeRemoveRow` hook. There may be new values.
477
477
  const numberOfRemovedIndexes = removedPhysicalIndexes.length;
478
478
  this.filterData(rowIndex, numberOfRemovedIndexes, removedPhysicalIndexes);
479
-
480
- // TODO: Function `removeRow` should validate fully, probably above.
481
479
  if (rowIndex < this.hot.countRows()) {
482
480
  this.hot.rowIndexMapper.removeIndexes(removedPhysicalIndexes);
483
- const customDefinedColumns = isDefined(this.tableMeta.columns) || isDefined(this.tableMeta.dataSchema);
484
-
485
- // All rows have been removed. There shouldn't be any columns.
486
- if (this.hot.rowIndexMapper.getNotTrimmedIndexesLength() === 0 && customDefinedColumns === false) {
481
+ const preserveColumns = isDefined(this.tableMeta.columns) || isDefined(this.tableMeta.dataSchema) || this.tableMeta.colHeaders;
482
+ if (this.hot.rowIndexMapper.getNotTrimmedIndexesLength() === 0 && !preserveColumns) {
487
483
  this.hot.columnIndexMapper.setIndexesSequence([]);
488
484
  }
489
485
  }
@@ -546,13 +542,9 @@ class DataMap {
546
542
  }
547
543
  }
548
544
  }
549
-
550
- // TODO: Function `removeCol` should validate fully, probably above.
551
545
  if (columnIndex < this.hot.countCols()) {
552
546
  this.hot.columnIndexMapper.removeIndexes(removedPhysicalIndexes);
553
-
554
- // All columns have been removed. There shouldn't be any rows.
555
- if (this.hot.columnIndexMapper.getNotTrimmedIndexesLength() === 0) {
547
+ if (!this.tableMeta.rowHeaders && this.hot.columnIndexMapper.getNotTrimmedIndexesLength() === 0) {
556
548
  this.hot.rowIndexMapper.setIndexesSequence([]);
557
549
  }
558
550
  }
@@ -185,8 +185,8 @@ class DataSource {
185
185
  value = valueHolder.value;
186
186
  }
187
187
  }
188
- if (!Number.isInteger(row)) {
189
- // invalid row number
188
+ if (['__proto__', 'constructor', 'prototype'].includes(row)) {
189
+ // prevent prototype pollution
190
190
  return;
191
191
  }
192
192
  if (!Number.isInteger(column)) {
@@ -182,8 +182,8 @@ class DataSource {
182
182
  value = valueHolder.value;
183
183
  }
184
184
  }
185
- if (!Number.isInteger(row)) {
186
- // invalid row number
185
+ if (['__proto__', 'constructor', 'prototype'].includes(row)) {
186
+ // prevent prototype pollution
187
187
  return;
188
188
  }
189
189
  if (!Number.isInteger(column)) {
@@ -3858,8 +3858,8 @@ var _default = () => {
3858
3858
  /**
3859
3859
  * The `rowHeights` option sets rows' heights, in pixels.
3860
3860
  *
3861
- * In the rendering process, the default row height is 23 px (in the classic theme: 22 px + 1 px of the row's bottom border) or whatever is defined in the used theme (based on the line height, vertical padding and cell borders).
3862
- * You can change it to equal or greater than the defautl value, by setting the `rowHeights` option to one of the following:
3861
+ * In the rendering process, the default row height is `classic: 23px`, `main: 29px`, `horizon: 37px` (in the classic theme: 22px + 1px of the row's bottom border) or whatever is defined in the used theme (based on the line height, vertical padding and cell borders).
3862
+ * You can change it to equal or greater than the default value, by setting the `rowHeights` option to one of the following:
3863
3863
  *
3864
3864
  * | Setting | Description | Example |
3865
3865
  * | ----------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
@@ -3855,8 +3855,8 @@ export default () => {
3855
3855
  /**
3856
3856
  * The `rowHeights` option sets rows' heights, in pixels.
3857
3857
  *
3858
- * In the rendering process, the default row height is 23 px (in the classic theme: 22 px + 1 px of the row's bottom border) or whatever is defined in the used theme (based on the line height, vertical padding and cell borders).
3859
- * You can change it to equal or greater than the defautl value, by setting the `rowHeights` option to one of the following:
3858
+ * In the rendering process, the default row height is `classic: 23px`, `main: 29px`, `horizon: 37px` (in the classic theme: 22px + 1px of the row's bottom border) or whatever is defined in the used theme (based on the line height, vertical padding and cell borders).
3859
+ * You can change it to equal or greater than the default value, by setting the `rowHeights` option to one of the following:
3860
3860
  *
3861
3861
  * | Setting | Description | Example |
3862
3862
  * | ----------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |