handsontable 15.2.0 → 15.3.0-next-6f5f494-20250424

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 (224) hide show
  1. package/3rdparty/walkontable/src/cell/range.js +14 -0
  2. package/3rdparty/walkontable/src/cell/range.mjs +14 -0
  3. package/3rdparty/walkontable/src/core/_base.js +2 -2
  4. package/3rdparty/walkontable/src/core/_base.mjs +3 -3
  5. package/3rdparty/walkontable/src/overlay/_base.js +0 -2
  6. package/3rdparty/walkontable/src/overlay/_base.mjs +0 -2
  7. package/3rdparty/walkontable/src/overlay/bottom.js +9 -6
  8. package/3rdparty/walkontable/src/overlay/bottom.mjs +9 -6
  9. package/3rdparty/walkontable/src/overlay/inlineStart.js +8 -5
  10. package/3rdparty/walkontable/src/overlay/inlineStart.mjs +8 -5
  11. package/3rdparty/walkontable/src/overlay/top.js +11 -6
  12. package/3rdparty/walkontable/src/overlay/top.mjs +11 -6
  13. package/3rdparty/walkontable/src/overlays.js +15 -11
  14. package/3rdparty/walkontable/src/overlays.mjs +15 -11
  15. package/3rdparty/walkontable/src/renderer/rowHeaders.js +4 -1
  16. package/3rdparty/walkontable/src/renderer/rowHeaders.mjs +4 -1
  17. package/3rdparty/walkontable/src/selection/border/border.js +5 -0
  18. package/3rdparty/walkontable/src/selection/border/border.mjs +5 -0
  19. package/3rdparty/walkontable/src/table/mixin/stickyColumnsStart.js +3 -4
  20. package/3rdparty/walkontable/src/table/mixin/stickyColumnsStart.mjs +3 -4
  21. package/3rdparty/walkontable/src/table/mixin/stickyRowsBottom.js +8 -10
  22. package/3rdparty/walkontable/src/table/mixin/stickyRowsBottom.mjs +8 -10
  23. package/3rdparty/walkontable/src/table/mixin/stickyRowsTop.js +3 -4
  24. package/3rdparty/walkontable/src/table/mixin/stickyRowsTop.mjs +3 -4
  25. package/3rdparty/walkontable/src/table.js +5 -2
  26. package/3rdparty/walkontable/src/table.mjs +5 -2
  27. package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.js +0 -2
  28. package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.mjs +0 -2
  29. package/CHANGELOG.md +45 -1
  30. package/README.md +1 -1
  31. package/base.js +2 -2
  32. package/base.mjs +2 -2
  33. package/core/focusCatcher/focusDetector.js +1 -1
  34. package/core/focusCatcher/focusDetector.mjs +2 -2
  35. package/core/hooks/constants.js +8 -0
  36. package/core/hooks/constants.mjs +8 -0
  37. package/core/hooks/index.d.ts +1 -0
  38. package/core/viewportScroll/scrollStrategies/columnHeaderScroll.js +7 -5
  39. package/core/viewportScroll/scrollStrategies/columnHeaderScroll.mjs +7 -5
  40. package/core/viewportScroll/scrollStrategies/focusScroll.js +8 -1
  41. package/core/viewportScroll/scrollStrategies/focusScroll.mjs +8 -1
  42. package/core/viewportScroll/scrollStrategies/multipleScroll.js +13 -1
  43. package/core/viewportScroll/scrollStrategies/multipleScroll.mjs +13 -1
  44. package/core/viewportScroll/scrollStrategies/noncontiguousScroll.js +13 -1
  45. package/core/viewportScroll/scrollStrategies/noncontiguousScroll.mjs +13 -1
  46. package/core/viewportScroll/scrollStrategies/rowHeaderScroll.js +7 -5
  47. package/core/viewportScroll/scrollStrategies/rowHeaderScroll.mjs +7 -5
  48. package/core/viewportScroll/scrollStrategies/singleScroll.js +8 -4
  49. package/core/viewportScroll/scrollStrategies/singleScroll.mjs +8 -4
  50. package/core/viewportScroll/utils.js +111 -0
  51. package/core/viewportScroll/utils.mjs +106 -0
  52. package/core.d.ts +2 -3
  53. package/core.js +125 -71
  54. package/core.mjs +126 -72
  55. package/dataMap/dataMap.js +0 -7
  56. package/dataMap/dataMap.mjs +0 -7
  57. package/dataMap/metaManager/index.js +8 -9
  58. package/dataMap/metaManager/index.mjs +8 -9
  59. package/dataMap/metaManager/mods/dynamicCellMeta.js +4 -1
  60. package/dataMap/metaManager/mods/dynamicCellMeta.mjs +4 -1
  61. package/dist/handsontable.css +4 -15
  62. package/dist/handsontable.full.css +4 -17
  63. package/dist/handsontable.full.js +4573 -4013
  64. package/dist/handsontable.full.min.css +3 -3
  65. package/dist/handsontable.full.min.js +148 -148
  66. package/dist/handsontable.js +4287 -3730
  67. package/dist/handsontable.min.css +3 -3
  68. package/dist/handsontable.min.js +19 -19
  69. package/editorManager.js +1 -7
  70. package/editorManager.mjs +1 -7
  71. package/editors/autocompleteEditor/autocompleteEditor.js +31 -7
  72. package/editors/autocompleteEditor/autocompleteEditor.mjs +31 -7
  73. package/focusManager.js +4 -2
  74. package/focusManager.mjs +4 -2
  75. package/helpers/browser.js +1 -1
  76. package/helpers/browser.mjs +1 -1
  77. package/helpers/dom/element.d.ts +1 -0
  78. package/helpers/dom/element.js +20 -0
  79. package/helpers/dom/element.mjs +19 -0
  80. package/helpers/mixed.js +2 -2
  81. package/helpers/mixed.mjs +2 -2
  82. package/helpers/object.js +3 -0
  83. package/helpers/object.mjs +3 -0
  84. package/package.json +1 -1
  85. package/plugins/autoColumnSize/autoColumnSize.js +38 -17
  86. package/plugins/autoColumnSize/autoColumnSize.mjs +38 -17
  87. package/plugins/autoRowSize/autoRowSize.js +12 -6
  88. package/plugins/autoRowSize/autoRowSize.mjs +12 -6
  89. package/plugins/columnSorting/columnSorting.js +0 -4
  90. package/plugins/columnSorting/columnSorting.mjs +0 -4
  91. package/plugins/comments/comments.js +1 -0
  92. package/plugins/comments/comments.mjs +1 -0
  93. package/plugins/contextMenu/menu/defaultShortcutsList.js +2 -2
  94. package/plugins/contextMenu/menu/defaultShortcutsList.mjs +2 -2
  95. package/plugins/contextMenu/menu/menu.js +1 -0
  96. package/plugins/contextMenu/menu/menu.mjs +1 -0
  97. package/plugins/contextMenu/menu/positioner.js +10 -2
  98. package/plugins/contextMenu/menu/positioner.mjs +10 -2
  99. package/plugins/contextMenu/predefinedItems/redo.js +3 -3
  100. package/plugins/contextMenu/predefinedItems/redo.mjs +3 -3
  101. package/plugins/contextMenu/predefinedItems/undo.js +3 -3
  102. package/plugins/contextMenu/predefinedItems/undo.mjs +3 -3
  103. package/plugins/copyPaste/copyPaste.js +12 -9
  104. package/plugins/copyPaste/copyPaste.mjs +12 -9
  105. package/plugins/copyPaste/pasteEvent.js +3 -0
  106. package/plugins/copyPaste/pasteEvent.mjs +3 -0
  107. package/plugins/exportFile/exportFile.d.ts +1 -0
  108. package/plugins/exportFile/exportFile.js +2 -1
  109. package/plugins/exportFile/exportFile.mjs +2 -1
  110. package/plugins/exportFile/types/csv.js +76 -11
  111. package/plugins/exportFile/types/csv.mjs +76 -11
  112. package/plugins/filters/filters.js +24 -23
  113. package/plugins/filters/filters.mjs +24 -23
  114. package/plugins/filters/ui/multipleSelect.js +7 -1
  115. package/plugins/filters/ui/multipleSelect.mjs +7 -1
  116. package/plugins/formulas/formulas.d.ts +1 -1
  117. package/plugins/formulas/formulas.js +57 -60
  118. package/plugins/formulas/formulas.mjs +59 -62
  119. package/plugins/formulas/indexSyncer/axisSyncer.js +5 -1
  120. package/plugins/formulas/indexSyncer/axisSyncer.mjs +5 -1
  121. package/plugins/hiddenColumns/hiddenColumns.js +1 -1
  122. package/plugins/hiddenColumns/hiddenColumns.mjs +1 -1
  123. package/plugins/hiddenRows/hiddenRows.js +1 -1
  124. package/plugins/hiddenRows/hiddenRows.mjs +1 -1
  125. package/plugins/manualColumnResize/manualColumnResize.js +4 -6
  126. package/plugins/manualColumnResize/manualColumnResize.mjs +4 -6
  127. package/plugins/manualRowResize/manualRowResize.js +4 -6
  128. package/plugins/manualRowResize/manualRowResize.mjs +4 -6
  129. package/plugins/mergeCells/mergeCells.js +10 -30
  130. package/plugins/mergeCells/mergeCells.mjs +10 -30
  131. package/plugins/mergeCells/renderer.js +15 -0
  132. package/plugins/mergeCells/renderer.mjs +15 -0
  133. package/plugins/mergeCells/utils.js +31 -0
  134. package/plugins/mergeCells/utils.mjs +27 -0
  135. package/plugins/nestedRows/data/dataManager.js +2 -2
  136. package/plugins/nestedRows/data/dataManager.mjs +2 -2
  137. package/plugins/undoRedo/actions/index.js +0 -2
  138. package/plugins/undoRedo/actions/index.mjs +0 -2
  139. package/plugins/undoRedo/actions/removeColumn.js +19 -14
  140. package/plugins/undoRedo/actions/removeColumn.mjs +19 -14
  141. package/plugins/undoRedo/actions/removeRow.js +12 -4
  142. package/plugins/undoRedo/actions/removeRow.mjs +12 -4
  143. package/selection/selection.js +3 -1
  144. package/selection/selection.mjs +3 -1
  145. package/shortcutContexts/commands/extendCellsSelection/down.js +7 -2
  146. package/shortcutContexts/commands/extendCellsSelection/down.mjs +7 -2
  147. package/shortcutContexts/commands/extendCellsSelection/downByViewportHeight.js +8 -2
  148. package/shortcutContexts/commands/extendCellsSelection/downByViewportHeight.mjs +8 -2
  149. package/shortcutContexts/commands/extendCellsSelection/left.js +7 -2
  150. package/shortcutContexts/commands/extendCellsSelection/left.mjs +7 -2
  151. package/shortcutContexts/commands/extendCellsSelection/right.js +7 -2
  152. package/shortcutContexts/commands/extendCellsSelection/right.mjs +7 -2
  153. package/shortcutContexts/commands/extendCellsSelection/toColumns.js +7 -2
  154. package/shortcutContexts/commands/extendCellsSelection/toColumns.mjs +7 -2
  155. package/shortcutContexts/commands/extendCellsSelection/toMostBottom.js +3 -1
  156. package/shortcutContexts/commands/extendCellsSelection/toMostBottom.mjs +3 -1
  157. package/shortcutContexts/commands/extendCellsSelection/toMostInlineEnd.js +3 -1
  158. package/shortcutContexts/commands/extendCellsSelection/toMostInlineEnd.mjs +3 -1
  159. package/shortcutContexts/commands/extendCellsSelection/toMostInlineStart.js +3 -1
  160. package/shortcutContexts/commands/extendCellsSelection/toMostInlineStart.mjs +3 -1
  161. package/shortcutContexts/commands/extendCellsSelection/toMostLeft.js +3 -1
  162. package/shortcutContexts/commands/extendCellsSelection/toMostLeft.mjs +3 -1
  163. package/shortcutContexts/commands/extendCellsSelection/toMostRight.js +3 -1
  164. package/shortcutContexts/commands/extendCellsSelection/toMostRight.mjs +3 -1
  165. package/shortcutContexts/commands/extendCellsSelection/toMostTop.js +3 -1
  166. package/shortcutContexts/commands/extendCellsSelection/toMostTop.mjs +3 -1
  167. package/shortcutContexts/commands/extendCellsSelection/toRows.js +7 -2
  168. package/shortcutContexts/commands/extendCellsSelection/toRows.mjs +7 -2
  169. package/shortcutContexts/commands/extendCellsSelection/up.js +7 -2
  170. package/shortcutContexts/commands/extendCellsSelection/up.mjs +7 -2
  171. package/shortcutContexts/commands/extendCellsSelection/upByViewportHeight.js +8 -2
  172. package/shortcutContexts/commands/extendCellsSelection/upByViewportHeight.mjs +8 -2
  173. package/shortcutContexts/commands/index.js +0 -2
  174. package/shortcutContexts/commands/index.mjs +0 -2
  175. package/shortcutContexts/commands/moveCellSelection/down.js +2 -0
  176. package/shortcutContexts/commands/moveCellSelection/down.mjs +2 -0
  177. package/shortcutContexts/commands/moveCellSelection/downByViewportHeight.js +6 -1
  178. package/shortcutContexts/commands/moveCellSelection/downByViewportHeight.mjs +6 -1
  179. package/shortcutContexts/commands/moveCellSelection/inlineEnd.js +8 -3
  180. package/shortcutContexts/commands/moveCellSelection/inlineEnd.mjs +8 -3
  181. package/shortcutContexts/commands/moveCellSelection/inlineStart.js +8 -3
  182. package/shortcutContexts/commands/moveCellSelection/inlineStart.mjs +8 -3
  183. package/shortcutContexts/commands/moveCellSelection/left.js +6 -1
  184. package/shortcutContexts/commands/moveCellSelection/left.mjs +6 -1
  185. package/shortcutContexts/commands/moveCellSelection/right.js +6 -1
  186. package/shortcutContexts/commands/moveCellSelection/right.mjs +6 -1
  187. package/shortcutContexts/commands/moveCellSelection/toMostBottom.js +4 -1
  188. package/shortcutContexts/commands/moveCellSelection/toMostBottom.mjs +4 -1
  189. package/shortcutContexts/commands/moveCellSelection/toMostBottomInlineEnd.js +2 -0
  190. package/shortcutContexts/commands/moveCellSelection/toMostBottomInlineEnd.mjs +2 -0
  191. package/shortcutContexts/commands/moveCellSelection/toMostInlineEnd.js +2 -0
  192. package/shortcutContexts/commands/moveCellSelection/toMostInlineEnd.mjs +2 -0
  193. package/shortcutContexts/commands/moveCellSelection/toMostInlineStart.js +2 -0
  194. package/shortcutContexts/commands/moveCellSelection/toMostInlineStart.mjs +2 -0
  195. package/shortcutContexts/commands/moveCellSelection/toMostLeft.js +2 -0
  196. package/shortcutContexts/commands/moveCellSelection/toMostLeft.mjs +2 -0
  197. package/shortcutContexts/commands/moveCellSelection/toMostRight.js +2 -0
  198. package/shortcutContexts/commands/moveCellSelection/toMostRight.mjs +2 -0
  199. package/shortcutContexts/commands/moveCellSelection/toMostTop.js +6 -1
  200. package/shortcutContexts/commands/moveCellSelection/toMostTop.mjs +6 -1
  201. package/shortcutContexts/commands/moveCellSelection/toMostTopInlineStart.js +2 -0
  202. package/shortcutContexts/commands/moveCellSelection/toMostTopInlineStart.mjs +2 -0
  203. package/shortcutContexts/commands/moveCellSelection/up.js +2 -0
  204. package/shortcutContexts/commands/moveCellSelection/up.mjs +2 -0
  205. package/shortcutContexts/commands/moveCellSelection/upByViewportHeight.js +6 -1
  206. package/shortcutContexts/commands/moveCellSelection/upByViewportHeight.mjs +6 -1
  207. package/shortcutContexts/commands/selectAllCells.js +7 -2
  208. package/shortcutContexts/commands/selectAllCells.mjs +7 -2
  209. package/shortcutContexts/commands/selectAllCellsAndHeaders.js +7 -2
  210. package/shortcutContexts/commands/selectAllCellsAndHeaders.mjs +7 -2
  211. package/shortcutContexts/index.js +2 -2
  212. package/shortcutContexts/index.mjs +0 -2
  213. package/styles/handsontable.css +15 -17
  214. package/styles/handsontable.min.css +3 -3
  215. package/styles/ht-theme-horizon.css +2 -2
  216. package/styles/ht-theme-horizon.min.css +2 -2
  217. package/styles/ht-theme-main.css +2 -2
  218. package/styles/ht-theme-main.min.css +2 -2
  219. package/tableView.js +5 -8
  220. package/tableView.mjs +5 -8
  221. package/translations/indexMapper.js +0 -1
  222. package/translations/indexMapper.mjs +0 -1
  223. package/utils/ghostTable.js +3 -0
  224. package/utils/ghostTable.mjs +3 -0
@@ -0,0 +1,106 @@
1
+ import { isHTMLElement } from "../../helpers/dom/element.mjs";
2
+ /**
3
+ * Scrolls the browser's viewport to the specified element.
4
+ *
5
+ * @param {HTMLElement} element The element to scroll.
6
+ */
7
+ export function scrollWindowToCell(element) {
8
+ if (isHTMLElement(element)) {
9
+ element.scrollIntoView({
10
+ block: 'nearest',
11
+ inline: 'nearest'
12
+ });
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Creates a scroll target calculator that calculates the target row and column best viewport
18
+ * scroll position based on the current selection.
19
+ *
20
+ * @param {Core} hotInstance The Handsontable instance.
21
+ * @returns {{ getComputedColumnTarget: Function, getComputedRowTarget: Function }}
22
+ */
23
+ export function createScrollTargetCalculator(hotInstance) {
24
+ const {
25
+ selection,
26
+ view
27
+ } = hotInstance;
28
+ const cellRange = hotInstance.getSelectedRangeLast();
29
+ const source = selection.getSelectionSource();
30
+ const firstVisibleColumn = view.getFirstFullyVisibleColumn();
31
+ const lastVisibleColumn = view.getLastFullyVisibleColumn();
32
+ const selectionFirstColumn = cellRange.getTopStartCorner().col;
33
+ const selectionLastColumn = cellRange.getBottomEndCorner().col;
34
+ const isSelectionOutsideStartViewport = selectionFirstColumn <= firstVisibleColumn;
35
+ const isSelectionOutsideEndViewport = selectionLastColumn >= lastVisibleColumn;
36
+ const firstVisibleRow = view.getFirstFullyVisibleRow();
37
+ const lastVisibleRow = view.getLastFullyVisibleRow();
38
+ const selectionFirstRow = cellRange.getTopStartCorner().row;
39
+ const selectionLastRow = cellRange.getBottomEndCorner().row;
40
+ const isSelectionOutsideTopViewport = selectionFirstRow <= firstVisibleRow;
41
+ const isSelectionOutsideBottomViewport = selectionLastRow >= lastVisibleRow;
42
+ return {
43
+ /**
44
+ * Calculates the target column for scrolling.
45
+ *
46
+ * @param {CellCoords} lastSelectionCoords The last selection coordinates.
47
+ * @returns {number}
48
+ */
49
+ getComputedColumnTarget(lastSelectionCoords) {
50
+ if (source === 'mouse' || source === 'keyboard') {
51
+ // For mouse or keyboard selection, always scroll to the last column
52
+ // defined by the last selection coords
53
+ return lastSelectionCoords.col;
54
+ }
55
+ if (isSelectionOutsideStartViewport && isSelectionOutsideEndViewport) {
56
+ // If the selection is outside both ends of the viewport, scroll to the
57
+ // column where the focused cell is located
58
+ return cellRange.highlight.col;
59
+ }
60
+ if (isSelectionOutsideStartViewport) {
61
+ // If the selection is outside the start (left) of the viewport, scroll to
62
+ // the first column of the selection range
63
+ return selectionFirstColumn;
64
+ }
65
+ if (isSelectionOutsideEndViewport) {
66
+ // If the selection is outside the end (right) of the viewport, scroll to
67
+ // the last column of the selection range
68
+ return selectionLastColumn;
69
+ }
70
+
71
+ // For other cases, scroll to the column defined by the last selection coords
72
+ return lastSelectionCoords.col;
73
+ },
74
+ /**
75
+ * Calculates the target row for scrolling.
76
+ *
77
+ * @param {CellCoords} lastSelectionCoords The last selection coordinates.
78
+ * @returns {number}
79
+ */
80
+ getComputedRowTarget(lastSelectionCoords) {
81
+ if (source === 'mouse' || source === 'keyboard') {
82
+ // For mouse or keyboard selection, always scroll to the last row
83
+ // defined by the coords
84
+ return lastSelectionCoords.row;
85
+ }
86
+ if (isSelectionOutsideTopViewport && isSelectionOutsideBottomViewport) {
87
+ // If the selection is outside both ends of the viewport, scroll to the
88
+ // row where the focused cell is located
89
+ return cellRange.highlight.row;
90
+ }
91
+ if (isSelectionOutsideTopViewport) {
92
+ // If the selection is outside the top of the viewport, scroll to
93
+ // the first row of the selection range
94
+ return selectionFirstRow;
95
+ }
96
+ if (isSelectionOutsideBottomViewport) {
97
+ // If the selection is outside the bottom of the viewport, scroll to
98
+ // the last row of the selection range
99
+ return selectionLastRow;
100
+ }
101
+
102
+ // For other cases, scroll to the row defined by the last selection coords
103
+ return lastSelectionCoords.row;
104
+ }
105
+ };
106
+ }
package/core.d.ts CHANGED
@@ -59,7 +59,7 @@ export default class Core {
59
59
  getCell(row: number, column: number, topmost?: boolean): HTMLTableCellElement | null;
60
60
  getCellEditor(cellMeta: CellMeta): BaseEditor;
61
61
  getCellEditor(row: number, column: number): BaseEditor;
62
- getCellMeta(row: number, column: number): CellProperties;
62
+ getCellMeta(row: number, column: number, options?: { skipMetaExtension: boolean }): CellProperties;
63
63
  getCellMetaAtRow(row: number): CellProperties[];
64
64
  getCellRenderer(cellMeta: CellMeta): BaseRenderer;
65
65
  getCellRenderer(row: number, column: number): BaseRenderer;
@@ -140,7 +140,6 @@ export default class Core {
140
140
  removeCellMeta(row: number, column: number, key: (keyof CellMeta) | string): void;
141
141
  removeHook<K extends keyof Events>(key: K, callback: Events[K]): void;
142
142
  render(): void;
143
- renderCall: boolean;
144
143
  resumeExecution(): void;
145
144
  resumeRender(): void;
146
145
  rootDocument: Document;
@@ -148,7 +147,7 @@ export default class Core {
148
147
  rootWindow: Window;
149
148
  rowIndexMapper: IndexMapper;
150
149
  runHooks(key: keyof Events, p1?: any, p2?: any, p3?: any, p4?: any, p5?: any, p6?: any): any;
151
- scrollViewportTo(options: { row?: number, col?: number, verticalSnap?: 'top' | 'bottom', horizontalSnap?: 'start' | 'end', considerHiddenIndexes?: boolean }): boolean;
150
+ scrollViewportTo(options: { row?: number, col?: number, verticalSnap?: 'top' | 'bottom', horizontalSnap?: 'start' | 'end', considerHiddenIndexes?: boolean }, callback?: () => void): boolean;
152
151
  scrollViewportTo(row?: number, column?: number, snapToBottom?: boolean, snapToRight?: boolean, considerHiddenIndexes?: boolean): boolean;
153
152
  scrollToFocusedCell(callback?: () => void): void;
154
153
  selectAll(includeRowHeaders?: boolean, includeColumnHeaders?: boolean, options?: { focusPosition?: SimpleCellCoords | CellCoords, disableHeadersHighlight?: boolean }): void;
package/core.js CHANGED
@@ -4,6 +4,7 @@ exports.__esModule = true;
4
4
  exports.default = Core;
5
5
  require("core-js/modules/es.error.cause.js");
6
6
  require("core-js/modules/es.array.push.js");
7
+ require("core-js/modules/es.object.from-entries.js");
7
8
  require("core-js/modules/es.set.difference.v2.js");
8
9
  require("core-js/modules/es.set.intersection.v2.js");
9
10
  require("core-js/modules/es.set.is-disjoint-from.v2.js");
@@ -226,12 +227,15 @@ function Core(rootElement, userSettings) {
226
227
  return instance.isLtr() ? 1 : -1;
227
228
  };
228
229
  userSettings.language = (0, _registry5.getValidLanguageCode)(userSettings.language);
229
- const metaManager = new _dataMap.MetaManager(instance, userSettings, [_dataMap.DynamicCellMetaMod, _dataMap.ExtendMetaPropertiesMod]);
230
+ const settingsWithoutHooks = Object.fromEntries(Object.entries(userSettings).filter(_ref => {
231
+ let [key] = _ref;
232
+ return !(_hooks.Hooks.getSingleton().isRegistered(key) || _hooks.Hooks.getSingleton().isDeprecated(key));
233
+ }));
234
+ const metaManager = new _dataMap.MetaManager(instance, settingsWithoutHooks, [_dataMap.DynamicCellMetaMod, _dataMap.ExtendMetaPropertiesMod]);
230
235
  const tableMeta = metaManager.getTableMeta();
231
236
  const globalMeta = metaManager.getGlobalMeta();
232
237
  const pluginsRegistry = (0, _uniqueMap.createUniqueMap)();
233
238
  this.container = this.rootDocument.createElement('div');
234
- this.renderCall = false;
235
239
  rootElement.insertBefore(this.container, rootElement.firstChild);
236
240
  if ((0, _rootInstance.isRootInstance)(this)) {
237
241
  (0, _mixed._injectProductInfo)(userSettings.licenseKey, rootElement);
@@ -263,6 +267,9 @@ function Core(rootElement, userSettings) {
263
267
  this.rowIndexMapper.addLocalHook('indexesSequenceChange', source => {
264
268
  instance.runHooks('afterRowSequenceChange', source);
265
269
  });
270
+ eventManager.addEventListener(this.rootDocument.documentElement, 'compositionstart', event => {
271
+ instance.runHooks('beforeCompositionStart', event);
272
+ });
266
273
  dataSource = new _dataSource.default(instance);
267
274
  if (!this.rootElement.id || this.rootElement.id.substring(0, 3) === 'ht_') {
268
275
  this.rootElement.id = this.guid; // if root element does not have an id, assign a random id
@@ -338,10 +345,11 @@ function Core(rootElement, userSettings) {
338
345
  }
339
346
  });
340
347
  this.selection = selection;
341
- const onIndexMapperCacheUpdate = _ref => {
348
+ const onIndexMapperCacheUpdate = _ref2 => {
342
349
  let {
343
350
  hiddenIndexesChanged
344
- } = _ref;
351
+ } = _ref2;
352
+ this.forceFullRender = true;
345
353
  if (hiddenIndexesChanged) {
346
354
  this.selection.commit();
347
355
  }
@@ -520,9 +528,9 @@ function Core(rootElement, userSettings) {
520
528
  const sortedIndexes = [...indexes];
521
529
 
522
530
  // Sort the indexes in ascending order.
523
- sortedIndexes.sort((_ref2, _ref3) => {
524
- let [indexA] = _ref2;
525
- let [indexB] = _ref3;
531
+ sortedIndexes.sort((_ref3, _ref4) => {
532
+ let [indexA] = _ref3;
533
+ let [indexB] = _ref4;
526
534
  if (indexA === indexB) {
527
535
  return 0;
528
536
  }
@@ -530,8 +538,8 @@ function Core(rootElement, userSettings) {
530
538
  });
531
539
 
532
540
  // Normalize the {index, amount} groups into bigger groups.
533
- const normalizedIndexes = (0, _array.arrayReduce)(sortedIndexes, (acc, _ref4) => {
534
- let [groupIndex, groupAmount] = _ref4;
541
+ const normalizedIndexes = (0, _array.arrayReduce)(sortedIndexes, (acc, _ref5) => {
542
+ let [groupIndex, groupAmount] = _ref5;
535
543
  const previousItem = acc[acc.length - 1];
536
544
  const [prevIndex, prevAmount] = previousItem;
537
545
  const prevLastIndex = prevIndex + prevAmount;
@@ -599,8 +607,8 @@ function Core(rootElement, userSettings) {
599
607
  let offset = 0;
600
608
 
601
609
  // Normalize the {index, amount} groups into bigger groups.
602
- (0, _array.arrayEach)(indexes, _ref5 => {
603
- let [groupIndex, groupAmount] = _ref5;
610
+ (0, _array.arrayEach)(indexes, _ref6 => {
611
+ let [groupIndex, groupAmount] = _ref6;
604
612
  const calcIndex = (0, _mixed.isEmpty)(groupIndex) ? instance.countRows() - 1 : Math.max(groupIndex - offset, 0);
605
613
 
606
614
  // If the 'index' is an integer decrease it by 'offset' otherwise pass it through to make the value
@@ -625,13 +633,6 @@ function Core(rootElement, userSettings) {
625
633
  }
626
634
  }
627
635
  const totalRows = instance.countRows();
628
- if (totalRows === 0) {
629
- selection.deselect();
630
- } else if (source === 'ContextMenu.removeRow') {
631
- selection.refresh();
632
- } else {
633
- selection.shiftRows(groupIndex, -groupAmount);
634
- }
635
636
  const fixedRowsTop = tableMeta.fixedRowsTop;
636
637
  if (fixedRowsTop >= calcIndex + 1) {
637
638
  tableMeta.fixedRowsTop -= Math.min(groupAmount, fixedRowsTop - calcIndex);
@@ -640,6 +641,13 @@ function Core(rootElement, userSettings) {
640
641
  if (fixedRowsBottom && calcIndex >= totalRows - fixedRowsBottom) {
641
642
  tableMeta.fixedRowsBottom -= Math.min(groupAmount, fixedRowsBottom);
642
643
  }
644
+ if (totalRows === 0) {
645
+ selection.deselect();
646
+ } else if (source === 'ContextMenu.removeRow') {
647
+ selection.refresh();
648
+ } else {
649
+ selection.shiftRows(groupIndex, -groupAmount);
650
+ }
643
651
  offset += groupAmount;
644
652
  });
645
653
  };
@@ -654,8 +662,8 @@ function Core(rootElement, userSettings) {
654
662
  let offset = 0;
655
663
 
656
664
  // Normalize the {index, amount} groups into bigger groups.
657
- (0, _array.arrayEach)(indexes, _ref6 => {
658
- let [groupIndex, groupAmount] = _ref6;
665
+ (0, _array.arrayEach)(indexes, _ref7 => {
666
+ let [groupIndex, groupAmount] = _ref7;
659
667
  const calcIndex = (0, _mixed.isEmpty)(groupIndex) ? instance.countCols() - 1 : Math.max(groupIndex - offset, 0);
660
668
  let physicalColumnIndex = instance.toPhysicalColumn(calcIndex);
661
669
 
@@ -1033,7 +1041,7 @@ function Core(rootElement, userSettings) {
1033
1041
  if ((0, _browser.isMobileBrowser)() || (0, _browser.isIpadOS)()) {
1034
1042
  (0, _element.addClass)(instance.rootElement, 'mobile');
1035
1043
  }
1036
- this.updateSettings(tableMeta, true);
1044
+ this.updateSettings(userSettings, true);
1037
1045
  this.view = new _tableView.default(this);
1038
1046
  const themeName = tableMeta.themeName || (0, _themes.getThemeClassName)(instance.rootElement);
1039
1047
 
@@ -1049,8 +1057,7 @@ function Core(rootElement, userSettings) {
1049
1057
  (0, _index.installFocusCatcher)(instance);
1050
1058
  }
1051
1059
  instance.runHooks('init');
1052
- this.forceFullRender = true; // used when data was changed
1053
- this.view.render();
1060
+ this.render();
1054
1061
 
1055
1062
  // Run the logic only if it's the table's initialization and the root element is not visible.
1056
1063
  if (!!firstRun && instance.rootElement.offsetParent === null) {
@@ -1223,13 +1230,11 @@ function Core(rootElement, userSettings) {
1223
1230
  datamap.set(changes[i][0], changes[i][1], changes[i][3]);
1224
1231
  }
1225
1232
  const hasChanges = changes.length > 0;
1226
- instance.forceFullRender = true; // used when data was changed or when all cells need to be re-rendered
1227
-
1228
1233
  if (hasChanges) {
1229
1234
  grid.adjustRowsAndCols();
1230
1235
  instance.runHooks('beforeChangeRender', changes, source);
1231
1236
  editorManager.closeEditor();
1232
- instance.view.render();
1237
+ instance.render();
1233
1238
  editorManager.prepareEditor();
1234
1239
  instance.view.adjustElementsSize();
1235
1240
  instance.runHooks('afterChange', changes, source || 'edit');
@@ -1238,7 +1243,7 @@ function Core(rootElement, userSettings) {
1238
1243
  activeEditor.refreshValue();
1239
1244
  }
1240
1245
  } else {
1241
- instance.view.render();
1246
+ instance.render();
1242
1247
  }
1243
1248
  }
1244
1249
 
@@ -1388,9 +1393,22 @@ function Core(rootElement, userSettings) {
1388
1393
  ...tableMeta
1389
1394
  };
1390
1395
  }
1391
- if (cellProperties.type === 'numeric' && typeof newValue === 'string' && (0, _number.isNumericLike)(newValue)) {
1396
+ const {
1397
+ type,
1398
+ checkedTemplate,
1399
+ uncheckedTemplate
1400
+ } = cellProperties;
1401
+ if (type === 'numeric' && typeof newValue === 'string' && (0, _number.isNumericLike)(newValue)) {
1392
1402
  filteredChanges[i][3] = getParsedNumber(newValue);
1393
1403
  }
1404
+ if (type === 'checkbox') {
1405
+ const stringifiedValue = (0, _mixed.stringify)(newValue);
1406
+ const isChecked = stringifiedValue === (0, _mixed.stringify)(checkedTemplate);
1407
+ const isUnchecked = stringifiedValue === (0, _mixed.stringify)(uncheckedTemplate);
1408
+ if (isChecked || isUnchecked) {
1409
+ filteredChanges[i][3] = isChecked ? checkedTemplate : uncheckedTemplate;
1410
+ }
1411
+ }
1394
1412
  }
1395
1413
  return filteredChanges;
1396
1414
  }
@@ -1614,11 +1632,11 @@ function Core(rootElement, userSettings) {
1614
1632
  this.getSelected = function () {
1615
1633
  // https://github.com/handsontable/handsontable/issues/44 //cjl
1616
1634
  if (selection.isSelected()) {
1617
- return (0, _array.arrayMap)(selection.getSelectedRange(), _ref7 => {
1635
+ return (0, _array.arrayMap)(selection.getSelectedRange(), _ref8 => {
1618
1636
  let {
1619
1637
  from,
1620
1638
  to
1621
- } = _ref7;
1639
+ } = _ref8;
1622
1640
  return [from.row, from.col, to.row, to.col];
1623
1641
  });
1624
1642
  }
@@ -1792,11 +1810,7 @@ function Core(rootElement, userSettings) {
1792
1810
  const nextValue = this.renderSuspendedCounter - 1;
1793
1811
  this.renderSuspendedCounter = Math.max(nextValue, 0);
1794
1812
  if (!this.isRenderSuspended() && nextValue === this.renderSuspendedCounter) {
1795
- if (this.renderCall) {
1796
- this.render();
1797
- } else {
1798
- instance.view.render();
1799
- }
1813
+ instance.view.render();
1800
1814
  }
1801
1815
  };
1802
1816
 
@@ -1812,9 +1826,8 @@ function Core(rootElement, userSettings) {
1812
1826
  */
1813
1827
  this.render = function () {
1814
1828
  if (this.view) {
1815
- this.renderCall = true;
1816
- this.forceFullRender = true; // used when data was changed or when all cells need to be re-rendered
1817
-
1829
+ // used when data was changed or when all cells need to be re-rendered (slow render)
1830
+ this.forceFullRender = true;
1818
1831
  if (!this.isRenderSuspended()) {
1819
1832
  instance.view.render();
1820
1833
  }
@@ -2307,23 +2320,27 @@ function Core(rootElement, userSettings) {
2307
2320
  if ((0, _mixed.isDefined)(settings.ganttChart)) {
2308
2321
  throw new Error('Since 8.0.0 the "ganttChart" setting is no longer supported.');
2309
2322
  }
2323
+ if (settings.language) {
2324
+ setLanguage(settings.language);
2325
+ }
2310
2326
 
2311
2327
  // eslint-disable-next-line no-restricted-syntax
2312
2328
  for (i in settings) {
2313
- if (i === 'data') {
2314
- // Do nothing. loadData will be triggered later
2315
- } else if (i === 'language') {
2316
- setLanguage(settings.language);
2329
+ if (i === 'data' || i === 'language') {
2330
+ // Do nothing. loadData and language change will be triggered later
2317
2331
  } else if (i === 'className') {
2318
2332
  setClassName('className', settings.className);
2319
2333
  } else if (i === 'tableClassName' && instance.table) {
2320
2334
  setClassName('tableClassName', settings.tableClassName);
2321
2335
  instance.view._wt.wtOverlays.syncOverlayTableClassNames();
2322
2336
  } else if (_hooks.Hooks.getSingleton().isRegistered(i) || _hooks.Hooks.getSingleton().isDeprecated(i)) {
2323
- if ((0, _function.isFunction)(settings[i])) {
2324
- _hooks.Hooks.getSingleton().addAsFixed(i, settings[i], instance);
2325
- } else if (Array.isArray(settings[i])) {
2326
- _hooks.Hooks.getSingleton().add(i, settings[i], instance);
2337
+ const hook = settings[i];
2338
+ if ((0, _function.isFunction)(hook)) {
2339
+ _hooks.Hooks.getSingleton().addAsFixed(i, hook, instance);
2340
+ tableMeta[i] = hook;
2341
+ } else if (Array.isArray(hook)) {
2342
+ _hooks.Hooks.getSingleton().add(i, hook, instance);
2343
+ tableMeta[i] = hook;
2327
2344
  }
2328
2345
  } else if (!init && (0, _object.hasOwnProperty)(settings, i)) {
2329
2346
  // Update settings
@@ -2427,8 +2444,7 @@ function Core(rootElement, userSettings) {
2427
2444
  }
2428
2445
  grid.adjustRowsAndCols();
2429
2446
  if (instance.view && !firstRun) {
2430
- instance.forceFullRender = true; // used when data was changed
2431
- instance.view.render();
2447
+ instance.render();
2432
2448
  instance.view._wt.wtOverlays.adjustElementsSize();
2433
2449
  }
2434
2450
  if (!init && instance.view && (currentHeight === '' || height === '' || height === undefined) && currentHeight !== height) {
@@ -2857,15 +2873,15 @@ function Core(rootElement, userSettings) {
2857
2873
  const isThereAnySetSourceListener = this.hasHook('afterSetSourceDataAtCell');
2858
2874
  const changesForHook = [];
2859
2875
  if (isThereAnySetSourceListener) {
2860
- (0, _array.arrayEach)(input, _ref8 => {
2861
- let [changeRow, changeProp, changeValue] = _ref8;
2876
+ (0, _array.arrayEach)(input, _ref9 => {
2877
+ let [changeRow, changeProp, changeValue] = _ref9;
2862
2878
  changesForHook.push([changeRow, changeProp, dataSource.getAtCell(changeRow, changeProp),
2863
2879
  // The previous value.
2864
2880
  changeValue]);
2865
2881
  });
2866
2882
  }
2867
- (0, _array.arrayEach)(input, _ref9 => {
2868
- let [changeRow, changeProp, changeValue] = _ref9;
2883
+ (0, _array.arrayEach)(input, _ref10 => {
2884
+ let [changeRow, changeProp, changeValue] = _ref10;
2869
2885
  dataSource.setAtCell(changeRow, changeProp, changeValue);
2870
2886
  });
2871
2887
  if (isThereAnySetSourceListener) {
@@ -3085,11 +3101,16 @@ function Core(rootElement, userSettings) {
3085
3101
  * @function getCellMeta
3086
3102
  * @param {number} row Visual row index.
3087
3103
  * @param {number} column Visual column index.
3104
+ * @param {object} options Execution options for the `getCellMeta` method.
3105
+ * @param {boolean} [options.skipMetaExtension=false] If `true`, skips extending the cell meta object. This means, the `cells` function, as well as the `afterGetCellMeta` and `beforeGetCellMeta` hooks, will not be called.
3088
3106
  * @returns {object} The cell properties object.
3089
3107
  * @fires Hooks#beforeGetCellMeta
3090
3108
  * @fires Hooks#afterGetCellMeta
3091
3109
  */
3092
3110
  this.getCellMeta = function (row, column) {
3111
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
3112
+ skipMetaExtension: false
3113
+ };
3093
3114
  let physicalRow = this.toPhysicalRow(row);
3094
3115
  let physicalColumn = this.toPhysicalColumn(column);
3095
3116
  if (physicalRow === null) {
@@ -3100,7 +3121,8 @@ function Core(rootElement, userSettings) {
3100
3121
  }
3101
3122
  return metaManager.getCellMeta(physicalRow, physicalColumn, {
3102
3123
  visualRow: row,
3103
- visualColumn: column
3124
+ visualColumn: column,
3125
+ ...options
3104
3126
  });
3105
3127
  };
3106
3128
 
@@ -4077,6 +4099,8 @@ function Core(rootElement, userSettings) {
4077
4099
  * col: 50,
4078
4100
  * verticalSnap: 'bottom',
4079
4101
  * horizontalSnap: 'end',
4102
+ * }, () => {
4103
+ * // callback function executed after the viewport is scrolled
4080
4104
  * });
4081
4105
  * ```
4082
4106
  *
@@ -4099,9 +4123,10 @@ function Core(rootElement, userSettings) {
4099
4123
  * be positioned at the start or end of the viewport.
4100
4124
  * @param {boolean} [options.considerHiddenIndexes=true] If `true`, we handle visual indexes, otherwise we handle only indexes which
4101
4125
  * may be rendered when they are in the viewport (we don't consider hidden indexes as they aren't rendered).
4126
+ * @param {Function} [callback] The callback function to call after the viewport is scrolled.
4102
4127
  * @returns {boolean} `true` if viewport was scrolled, `false` otherwise.
4103
4128
  */
4104
- this.scrollViewportTo = function (options) {
4129
+ this.scrollViewportTo = function (options, callback) {
4105
4130
  // Support for backward compatibility arguments: (row, col, snapToBottom, snapToRight, considerHiddenIndexes)
4106
4131
  if (typeof options === 'number') {
4107
4132
  var _arguments$;
@@ -4122,6 +4147,9 @@ function Core(rootElement, userSettings) {
4122
4147
  } = options !== null && options !== void 0 ? options : {};
4123
4148
  let renderableRow = row;
4124
4149
  let renderableColumn = col;
4150
+ if ((0, _function.isFunction)(callback)) {
4151
+ this.addHookOnce('afterScroll', callback);
4152
+ }
4125
4153
  if (considerHiddenIndexes === undefined || considerHiddenIndexes) {
4126
4154
  const isValidRowGrid = Number.isInteger(row) && row >= 0;
4127
4155
  const isValidColumnGrid = Number.isInteger(col) && col >= 0;
@@ -4135,16 +4163,24 @@ function Core(rootElement, userSettings) {
4135
4163
  }
4136
4164
  const isRowInteger = Number.isInteger(renderableRow);
4137
4165
  const isColumnInteger = Number.isInteger(renderableColumn);
4166
+ let isScrolled = false;
4138
4167
  if (isRowInteger && renderableRow >= 0 && isColumnInteger && renderableColumn >= 0) {
4139
- return instance.view.scrollViewport(instance._createCellCoords(renderableRow, renderableColumn), options.horizontalSnap, options.verticalSnap);
4140
- }
4141
- if (isRowInteger && renderableRow >= 0 && (isColumnInteger && renderableColumn < 0 || !isColumnInteger)) {
4142
- return instance.view.scrollViewportVertically(renderableRow, options.verticalSnap);
4143
- }
4144
- if (isColumnInteger && renderableColumn >= 0 && (isRowInteger && renderableRow < 0 || !isRowInteger)) {
4145
- return instance.view.scrollViewportHorizontally(renderableColumn, options.horizontalSnap);
4168
+ isScrolled = instance.view.scrollViewport(instance._createCellCoords(renderableRow, renderableColumn), options.horizontalSnap, options.verticalSnap);
4169
+ } else if (isRowInteger && renderableRow >= 0 && (isColumnInteger && renderableColumn < 0 || !isColumnInteger)) {
4170
+ isScrolled = instance.view.scrollViewportVertically(renderableRow, options.verticalSnap);
4171
+ } else if (isColumnInteger && renderableColumn >= 0 && (isRowInteger && renderableRow < 0 || !isRowInteger)) {
4172
+ isScrolled = instance.view.scrollViewportHorizontally(renderableColumn, options.horizontalSnap);
4173
+ }
4174
+ if ((0, _function.isFunction)(callback)) {
4175
+ if (isScrolled) {
4176
+ // fast render triggers `afterScroll` hook
4177
+ this.view.render();
4178
+ } else {
4179
+ this.removeHook('afterScroll', callback);
4180
+ this._registerMicrotask(() => callback());
4181
+ }
4146
4182
  }
4147
- return false;
4183
+ return isScrolled;
4148
4184
  };
4149
4185
 
4150
4186
  /**
@@ -4154,24 +4190,28 @@ function Core(rootElement, userSettings) {
4154
4190
  * @memberof Core#
4155
4191
  * @fires Hooks#afterScroll
4156
4192
  * @function scrollToFocusedCell
4157
- * @param {Function} callback The callback function to call after the viewport is scrolled.
4193
+ * @param {Function} [callback] The callback function to call after the viewport is scrolled.
4194
+ * @returns {boolean} `true` if the viewport was scrolled, `false` otherwise.
4158
4195
  */
4159
- this.scrollToFocusedCell = function () {
4160
- let callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : () => {};
4196
+ this.scrollToFocusedCell = function (callback) {
4161
4197
  if (!this.selection.isSelected()) {
4162
- return;
4198
+ return false;
4199
+ }
4200
+ if ((0, _function.isFunction)(callback)) {
4201
+ this.addHookOnce('afterScroll', callback);
4163
4202
  }
4164
- this.addHookOnce('afterScroll', callback);
4165
4203
  const {
4166
4204
  highlight
4167
4205
  } = this.getSelectedRangeLast();
4168
4206
  const isScrolled = this.scrollViewportTo(highlight.toObject());
4169
4207
  if (isScrolled) {
4208
+ // fast render triggers `afterScroll` hook
4170
4209
  this.view.render();
4171
- } else {
4210
+ } else if ((0, _function.isFunction)(callback)) {
4172
4211
  this.removeHook('afterScroll', callback);
4173
- this._registerImmediate(() => callback());
4212
+ this._registerMicrotask(() => callback());
4174
4213
  }
4214
+ return isScrolled;
4175
4215
  };
4176
4216
 
4177
4217
  /**
@@ -4212,8 +4252,8 @@ function Core(rootElement, userSettings) {
4212
4252
  instance.batchExecution(() => {
4213
4253
  instance.rowIndexMapper.unregisterAll();
4214
4254
  instance.columnIndexMapper.unregisterAll();
4215
- pluginsRegistry.getItems().forEach(_ref10 => {
4216
- let [, plugin] = _ref10;
4255
+ pluginsRegistry.getItems().forEach(_ref11 => {
4256
+ let [, plugin] = _ref11;
4217
4257
  plugin.destroy();
4218
4258
  });
4219
4259
  pluginsRegistry.clear();
@@ -4680,6 +4720,20 @@ function Core(rootElement, userSettings) {
4680
4720
  });
4681
4721
  };
4682
4722
 
4723
+ /**
4724
+ * Registers a microtask callback.
4725
+ *
4726
+ * @param {Function} callback Function to be delayed in execution.
4727
+ * @private
4728
+ */
4729
+ this._registerMicrotask = function (callback) {
4730
+ this.rootWindow.queueMicrotask(() => {
4731
+ if (!this.isDestroyed) {
4732
+ callback();
4733
+ }
4734
+ });
4735
+ };
4736
+
4683
4737
  /**
4684
4738
  * Gets the instance of the EditorManager.
4685
4739
  *