handsontable 0.0.0-next-ff10728-20250410 → 0.0.0-next-d9b3885-20250415

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.

Potentially problematic release.


This version of handsontable might be problematic. Click here for more details.

Files changed (122) 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/renderer/rowHeaders.js +4 -1
  4. package/3rdparty/walkontable/src/renderer/rowHeaders.mjs +4 -1
  5. package/3rdparty/walkontable/src/selection/border/border.js +5 -0
  6. package/3rdparty/walkontable/src/selection/border/border.mjs +5 -0
  7. package/3rdparty/walkontable/src/table/mixin/stickyColumnsStart.js +3 -4
  8. package/3rdparty/walkontable/src/table/mixin/stickyColumnsStart.mjs +3 -4
  9. package/3rdparty/walkontable/src/table/mixin/stickyRowsBottom.js +8 -10
  10. package/3rdparty/walkontable/src/table/mixin/stickyRowsBottom.mjs +8 -10
  11. package/3rdparty/walkontable/src/table/mixin/stickyRowsTop.js +3 -4
  12. package/3rdparty/walkontable/src/table/mixin/stickyRowsTop.mjs +3 -4
  13. package/3rdparty/walkontable/src/table.js +5 -2
  14. package/3rdparty/walkontable/src/table.mjs +5 -2
  15. package/CHANGELOG.md +39 -0
  16. package/base.js +2 -2
  17. package/base.mjs +2 -2
  18. package/core/focusCatcher/focusDetector.js +1 -1
  19. package/core/focusCatcher/focusDetector.mjs +2 -2
  20. package/core/hooks/constants.js +266 -0
  21. package/core/hooks/constants.mjs +266 -0
  22. package/core/hooks/index.d.ts +1 -0
  23. package/core.d.ts +0 -1
  24. package/core.js +71 -25
  25. package/core.mjs +72 -26
  26. package/dataMap/dataMap.js +0 -7
  27. package/dataMap/dataMap.mjs +0 -7
  28. package/dataMap/metaManager/metaSchema.js +28 -0
  29. package/dataMap/metaManager/metaSchema.mjs +28 -0
  30. package/dist/handsontable.css +3 -3
  31. package/dist/handsontable.full.css +3 -3
  32. package/dist/handsontable.full.js +1375 -350
  33. package/dist/handsontable.full.min.css +3 -3
  34. package/dist/handsontable.full.min.js +17 -17
  35. package/dist/handsontable.js +1375 -350
  36. package/dist/handsontable.min.css +3 -3
  37. package/dist/handsontable.min.js +18 -18
  38. package/editorManager.js +1 -7
  39. package/editorManager.mjs +1 -7
  40. package/editors/autocompleteEditor/autocompleteEditor.js +14 -4
  41. package/editors/autocompleteEditor/autocompleteEditor.mjs +14 -4
  42. package/editors/textEditor/textEditor.js +1 -1
  43. package/editors/textEditor/textEditor.mjs +2 -2
  44. package/helpers/browser.js +1 -1
  45. package/helpers/browser.mjs +1 -1
  46. package/helpers/dom/element.js +2 -2
  47. package/helpers/dom/element.mjs +1 -1
  48. package/helpers/mixed.js +2 -2
  49. package/helpers/mixed.mjs +2 -2
  50. package/helpers/object.js +3 -0
  51. package/helpers/object.mjs +3 -0
  52. package/package.json +1 -1
  53. package/plugins/autoColumnSize/autoColumnSize.js +48 -1
  54. package/plugins/autoColumnSize/autoColumnSize.mjs +48 -1
  55. package/plugins/autoRowSize/autoRowSize.js +46 -6
  56. package/plugins/autoRowSize/autoRowSize.mjs +46 -6
  57. package/plugins/bindRowsWithHeaders/bindRowsWithHeaders.js +13 -0
  58. package/plugins/bindRowsWithHeaders/bindRowsWithHeaders.mjs +13 -0
  59. package/plugins/collapsibleColumns/collapsibleColumns.js +31 -0
  60. package/plugins/collapsibleColumns/collapsibleColumns.mjs +31 -0
  61. package/plugins/columnSorting/columnSorting.js +0 -4
  62. package/plugins/columnSorting/columnSorting.mjs +0 -4
  63. package/plugins/columnSummary/columnSummary.js +33 -0
  64. package/plugins/columnSummary/columnSummary.mjs +33 -0
  65. package/plugins/comments/comments.js +54 -0
  66. package/plugins/comments/comments.mjs +54 -0
  67. package/plugins/contextMenu/menu/defaultShortcutsList.js +2 -2
  68. package/plugins/contextMenu/menu/defaultShortcutsList.mjs +2 -2
  69. package/plugins/contextMenu/menu/menu.js +1 -0
  70. package/plugins/contextMenu/menu/menu.mjs +1 -0
  71. package/plugins/contextMenu/menu/positioner.js +10 -2
  72. package/plugins/contextMenu/menu/positioner.mjs +10 -2
  73. package/plugins/copyPaste/copyPaste.js +12 -15
  74. package/plugins/copyPaste/copyPaste.mjs +13 -16
  75. package/plugins/copyPaste/pasteEvent.js +3 -0
  76. package/plugins/copyPaste/pasteEvent.mjs +3 -0
  77. package/plugins/dropdownMenu/dropdownMenu.js +15 -0
  78. package/plugins/dropdownMenu/dropdownMenu.mjs +15 -0
  79. package/plugins/exportFile/exportFile.js +58 -0
  80. package/plugins/exportFile/exportFile.mjs +58 -0
  81. package/plugins/filters/filters.js +99 -24
  82. package/plugins/filters/filters.mjs +99 -24
  83. package/plugins/filters/ui/multipleSelect.js +7 -1
  84. package/plugins/filters/ui/multipleSelect.mjs +7 -1
  85. package/plugins/hiddenColumns/hiddenColumns.js +65 -1
  86. package/plugins/hiddenColumns/hiddenColumns.mjs +65 -1
  87. package/plugins/hiddenRows/hiddenRows.js +65 -1
  88. package/plugins/hiddenRows/hiddenRows.mjs +65 -1
  89. package/plugins/manualColumnResize/manualColumnResize.js +4 -6
  90. package/plugins/manualColumnResize/manualColumnResize.mjs +4 -6
  91. package/plugins/manualRowResize/manualRowResize.js +4 -6
  92. package/plugins/manualRowResize/manualRowResize.mjs +4 -6
  93. package/plugins/mergeCells/mergeCells.js +26 -29
  94. package/plugins/mergeCells/mergeCells.mjs +26 -29
  95. package/plugins/mergeCells/renderer.js +15 -0
  96. package/plugins/mergeCells/renderer.mjs +15 -0
  97. package/plugins/mergeCells/utils.js +31 -0
  98. package/plugins/mergeCells/utils.mjs +27 -0
  99. package/plugins/nestedHeaders/nestedHeaders.js +25 -0
  100. package/plugins/nestedHeaders/nestedHeaders.mjs +25 -0
  101. package/plugins/nestedRows/data/dataManager.js +2 -2
  102. package/plugins/nestedRows/data/dataManager.mjs +2 -2
  103. package/plugins/stretchColumns/stretchColumns.js +13 -0
  104. package/plugins/stretchColumns/stretchColumns.mjs +13 -0
  105. package/plugins/trimRows/trimRows.js +61 -0
  106. package/plugins/trimRows/trimRows.mjs +61 -0
  107. package/plugins/undoRedo/actions/removeColumn.js +19 -14
  108. package/plugins/undoRedo/actions/removeColumn.mjs +19 -14
  109. package/plugins/undoRedo/actions/removeRow.js +12 -4
  110. package/plugins/undoRedo/actions/removeRow.mjs +12 -4
  111. package/selection/selection.js +3 -1
  112. package/selection/selection.mjs +3 -1
  113. package/styles/handsontable.css +14 -15
  114. package/styles/handsontable.min.css +3 -3
  115. package/styles/ht-theme-horizon.css +2 -2
  116. package/styles/ht-theme-horizon.min.css +2 -2
  117. package/styles/ht-theme-main.css +2 -2
  118. package/styles/ht-theme-main.min.css +2 -2
  119. package/tableView.js +5 -8
  120. package/tableView.mjs +5 -8
  121. package/utils/ghostTable.js +3 -0
  122. package/utils/ghostTable.mjs +3 -0
@@ -102,6 +102,37 @@ const actionDictionary = new Map([['collapse', {
102
102
  * />
103
103
  * ```
104
104
  * :::
105
+ *
106
+ * ::: only-for angular
107
+ * ```ts
108
+ * // Enable the collapsibleColumns plugin
109
+ * settings = {
110
+ * data: generateDataObj(),
111
+ * colHeaders: true,
112
+ * rowHeaders: true,
113
+ * nestedHeaders: true,
114
+ * // enable plugin
115
+ * collapsibleColumns: true,
116
+ * };
117
+ *
118
+ * // Or enable and configure specific collapsible columns
119
+ * settings = {
120
+ * data: generateDataObj(),
121
+ * colHeaders: true,
122
+ * rowHeaders: true,
123
+ * nestedHeaders: true,
124
+ * // enable and configure which columns can be collapsed
125
+ * collapsibleColumns: [
126
+ * { row: -4, col: 1, collapsible: true },
127
+ * { row: -3, col: 5, collapsible: true },
128
+ * ],
129
+ * };
130
+ * ```
131
+ *
132
+ * ```html
133
+ * <hot-table [settings]="settings"></hot-table>
134
+ * ```
135
+ * :::
105
136
  */
106
137
  var _collapsedColumnsMap = /*#__PURE__*/new WeakMap();
107
138
  var _CollapsibleColumns_brand = /*#__PURE__*/new WeakSet();
@@ -304,10 +304,6 @@ class ColumnSorting extends _base.BasePlugin {
304
304
  this.hot.runHooks('afterColumnSort', currentSortConfig, sortPossible ? destinationSortConfigs : currentSortConfig, sortPossible);
305
305
  if (sortPossible) {
306
306
  this.hot.render();
307
- // TODO: Workaround? This triggers fast redraw. One test won't pass after removal.
308
- // It should be refactored / described.
309
- this.hot.forceFullRender = false;
310
- this.hot.view.render();
311
307
  }
312
308
  }
313
309
 
@@ -301,10 +301,6 @@ export class ColumnSorting extends BasePlugin {
301
301
  this.hot.runHooks('afterColumnSort', currentSortConfig, sortPossible ? destinationSortConfigs : currentSortConfig, sortPossible);
302
302
  if (sortPossible) {
303
303
  this.hot.render();
304
- // TODO: Workaround? This triggers fast redraw. One test won't pass after removal.
305
- // It should be refactored / described.
306
- this.hot.forceFullRender = false;
307
- this.hot.view.render();
308
304
  }
309
305
  }
310
306
 
@@ -104,6 +104,39 @@ const PLUGIN_PRIORITY = exports.PLUGIN_PRIORITY = 220;
104
104
  * />
105
105
  * ```
106
106
  * :::
107
+ *
108
+ * ::: only-for angular
109
+ * ```ts
110
+ * settings = {
111
+ * data: getData(),
112
+ * colHeaders: true,
113
+ * rowHeaders: true,
114
+ * columnSummary: [
115
+ * {
116
+ * type: "min",
117
+ * destinationRow: 4,
118
+ * destinationColumn: 1,
119
+ * },
120
+ * {
121
+ * type: "max",
122
+ * destinationRow: 0,
123
+ * destinationColumn: 3,
124
+ * reversedRowCoords: true,
125
+ * },
126
+ * {
127
+ * type: "sum",
128
+ * destinationRow: 4,
129
+ * destinationColumn: 5,
130
+ * forceNumeric: true,
131
+ * },
132
+ * ],
133
+ * };
134
+ * ```
135
+ *
136
+ * ```html
137
+ * <hot-table [settings]="settings"></hot-table>
138
+ * ```
139
+ * :::
107
140
  */
108
141
  var _ColumnSummary_brand = /*#__PURE__*/new WeakSet();
109
142
  class ColumnSummary extends _base.BasePlugin {
@@ -100,6 +100,39 @@ export const PLUGIN_PRIORITY = 220;
100
100
  * />
101
101
  * ```
102
102
  * :::
103
+ *
104
+ * ::: only-for angular
105
+ * ```ts
106
+ * settings = {
107
+ * data: getData(),
108
+ * colHeaders: true,
109
+ * rowHeaders: true,
110
+ * columnSummary: [
111
+ * {
112
+ * type: "min",
113
+ * destinationRow: 4,
114
+ * destinationColumn: 1,
115
+ * },
116
+ * {
117
+ * type: "max",
118
+ * destinationRow: 0,
119
+ * destinationColumn: 3,
120
+ * reversedRowCoords: true,
121
+ * },
122
+ * {
123
+ * type: "sum",
124
+ * destinationRow: 4,
125
+ * destinationColumn: 5,
126
+ * forceNumeric: true,
127
+ * },
128
+ * ],
129
+ * };
130
+ * ```
131
+ *
132
+ * ```html
133
+ * <hot-table [settings]="settings"></hot-table>
134
+ * ```
135
+ * :::
103
136
  */
104
137
  var _ColumnSummary_brand = /*#__PURE__*/new WeakSet();
105
138
  export class ColumnSummary extends BasePlugin {
@@ -121,6 +121,59 @@ const SHORTCUTS_CONTEXT_NAME = `plugin:${PLUGIN_KEY}`;
121
121
  * commentsPlugin.removeComment();
122
122
  * ```
123
123
  * :::
124
+ *
125
+ * ::: only-for angular
126
+ * ```ts
127
+ * import { AfterViewInit, Component, ViewChild } from "@angular/core";
128
+ * import {
129
+ * GridSettings,
130
+ * HotTableModule,
131
+ * HotTableComponent,
132
+ * } from "@handsontable/angular-wrapper";
133
+ *
134
+ * `@Component`({
135
+ * selector: "app-example",
136
+ * standalone: true,
137
+ * imports: [HotTableModule],
138
+ * template: ` <div class="ht-theme-main">
139
+ * <hot-table [settings]="gridSettings" />
140
+ * </div>`,
141
+ * })
142
+ * export class ExampleComponent implements AfterViewInit {
143
+ * `@ViewChild`(HotTableComponent, { static: false })
144
+ * readonly hotTable!: HotTableComponent;
145
+ *
146
+ * readonly gridSettings = <GridSettings>{
147
+ * data: this.getData(),
148
+ * comments: true,
149
+ * cell: [
150
+ * { row: 1, col: 1, comment: { value: "Foo" } },
151
+ * { row: 2, col: 2, comment: { value: "Bar" } },
152
+ * ],
153
+ * };
154
+ *
155
+ * ngAfterViewInit(): void {
156
+ * // Access to plugin instance:
157
+ * const hot = this.hotTable.hotInstance;
158
+ * const commentsPlugin = hot.getPlugin("comments");
159
+ *
160
+ * // Manage comments programmatically:
161
+ * commentsPlugin.setCommentAtCell(1, 6, "Comment contents");
162
+ * commentsPlugin.showAtCell(1, 6);
163
+ * commentsPlugin.removeCommentAtCell(1, 6);
164
+ *
165
+ * // You can also set range once and use proper methods:
166
+ * commentsPlugin.setRange({ from: { row: 1, col: 6 } });
167
+ * commentsPlugin.setComment("Comment contents");
168
+ * commentsPlugin.show();
169
+ * }
170
+ *
171
+ * private getData(): any[] {
172
+ * // get some data
173
+ * }
174
+ * }
175
+ * ```
176
+ * :::
124
177
  */
125
178
  var _editor = /*#__PURE__*/new WeakMap();
126
179
  var _displaySwitch = /*#__PURE__*/new WeakMap();
@@ -234,6 +287,7 @@ class Comments extends _base.BasePlugin {
234
287
  this.addHook('afterScroll', () => _assertClassBrand(_Comments_brand, this, _onAfterScroll).call(this));
235
288
  this.addHook('afterBeginEditing', () => this.hide());
236
289
  this.addHook('afterDocumentKeyDown', event => _assertClassBrand(_Comments_brand, this, _onAfterDocumentKeyDown).call(this, event));
290
+ this.addHook('beforeCompositionStart', event => _assertClassBrand(_Comments_brand, this, _onAfterDocumentKeyDown).call(this, event));
237
291
  this.addHook('afterSetTheme', function () {
238
292
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
239
293
  args[_key2] = arguments[_key2];
@@ -117,6 +117,59 @@ const SHORTCUTS_CONTEXT_NAME = `plugin:${PLUGIN_KEY}`;
117
117
  * commentsPlugin.removeComment();
118
118
  * ```
119
119
  * :::
120
+ *
121
+ * ::: only-for angular
122
+ * ```ts
123
+ * import { AfterViewInit, Component, ViewChild } from "@angular/core";
124
+ * import {
125
+ * GridSettings,
126
+ * HotTableModule,
127
+ * HotTableComponent,
128
+ * } from "@handsontable/angular-wrapper";
129
+ *
130
+ * `@Component`({
131
+ * selector: "app-example",
132
+ * standalone: true,
133
+ * imports: [HotTableModule],
134
+ * template: ` <div class="ht-theme-main">
135
+ * <hot-table [settings]="gridSettings" />
136
+ * </div>`,
137
+ * })
138
+ * export class ExampleComponent implements AfterViewInit {
139
+ * `@ViewChild`(HotTableComponent, { static: false })
140
+ * readonly hotTable!: HotTableComponent;
141
+ *
142
+ * readonly gridSettings = <GridSettings>{
143
+ * data: this.getData(),
144
+ * comments: true,
145
+ * cell: [
146
+ * { row: 1, col: 1, comment: { value: "Foo" } },
147
+ * { row: 2, col: 2, comment: { value: "Bar" } },
148
+ * ],
149
+ * };
150
+ *
151
+ * ngAfterViewInit(): void {
152
+ * // Access to plugin instance:
153
+ * const hot = this.hotTable.hotInstance;
154
+ * const commentsPlugin = hot.getPlugin("comments");
155
+ *
156
+ * // Manage comments programmatically:
157
+ * commentsPlugin.setCommentAtCell(1, 6, "Comment contents");
158
+ * commentsPlugin.showAtCell(1, 6);
159
+ * commentsPlugin.removeCommentAtCell(1, 6);
160
+ *
161
+ * // You can also set range once and use proper methods:
162
+ * commentsPlugin.setRange({ from: { row: 1, col: 6 } });
163
+ * commentsPlugin.setComment("Comment contents");
164
+ * commentsPlugin.show();
165
+ * }
166
+ *
167
+ * private getData(): any[] {
168
+ * // get some data
169
+ * }
170
+ * }
171
+ * ```
172
+ * :::
120
173
  */
121
174
  var _editor = /*#__PURE__*/new WeakMap();
122
175
  var _displaySwitch = /*#__PURE__*/new WeakMap();
@@ -230,6 +283,7 @@ export class Comments extends BasePlugin {
230
283
  this.addHook('afterScroll', () => _assertClassBrand(_Comments_brand, this, _onAfterScroll).call(this));
231
284
  this.addHook('afterBeginEditing', () => this.hide());
232
285
  this.addHook('afterDocumentKeyDown', event => _assertClassBrand(_Comments_brand, this, _onAfterDocumentKeyDown).call(this, event));
286
+ this.addHook('beforeCompositionStart', event => _assertClassBrand(_Comments_brand, this, _onAfterDocumentKeyDown).call(this, event));
233
287
  this.addHook('afterSetTheme', function () {
234
288
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
235
289
  args[_key2] = arguments[_key2];
@@ -39,7 +39,7 @@ function createDefaultShortcutsList(menu) {
39
39
  keys: [['ArrowUp']],
40
40
  callback: () => menu.getNavigator().toPreviousItem()
41
41
  }, {
42
- keys: [['ArrowRight']],
42
+ keys: [[hot.isRtl() ? 'ArrowLeft' : 'ArrowRight']],
43
43
  callback: () => {
44
44
  const selection = hotMenu.getSelectedLast();
45
45
  if (selection) {
@@ -50,7 +50,7 @@ function createDefaultShortcutsList(menu) {
50
50
  }
51
51
  }
52
52
  }, {
53
- keys: [['ArrowLeft']],
53
+ keys: [[hot.isRtl() ? 'ArrowRight' : 'ArrowLeft']],
54
54
  callback: () => {
55
55
  const selection = hotMenu.getSelectedLast();
56
56
  if (selection && menu.isSubMenu()) {
@@ -35,7 +35,7 @@ export function createDefaultShortcutsList(menu) {
35
35
  keys: [['ArrowUp']],
36
36
  callback: () => menu.getNavigator().toPreviousItem()
37
37
  }, {
38
- keys: [['ArrowRight']],
38
+ keys: [[hot.isRtl() ? 'ArrowLeft' : 'ArrowRight']],
39
39
  callback: () => {
40
40
  const selection = hotMenu.getSelectedLast();
41
41
  if (selection) {
@@ -46,7 +46,7 @@ export function createDefaultShortcutsList(menu) {
46
46
  }
47
47
  }
48
48
  }, {
49
- keys: [['ArrowLeft']],
49
+ keys: [[hot.isRtl() ? 'ArrowRight' : 'ArrowLeft']],
50
50
  callback: () => {
51
51
  const selection = hotMenu.getSelectedLast();
52
52
  if (selection && menu.isSubMenu()) {
@@ -293,6 +293,7 @@ class Menu {
293
293
  layoutDirection: this.hot.isRtl() ? 'rtl' : 'ltr',
294
294
  ariaTags: false,
295
295
  themeName: this.hot.getCurrentThemeName(),
296
+ beforeRefreshDimensions: () => false,
296
297
  beforeOnCellMouseOver: (event, coords) => {
297
298
  _classPrivateFieldGet(_navigator, this).setCurrentPage(coords.row);
298
299
  },
@@ -289,6 +289,7 @@ export class Menu {
289
289
  layoutDirection: this.hot.isRtl() ? 'rtl' : 'ltr',
290
290
  ariaTags: false,
291
291
  themeName: this.hot.getCurrentThemeName(),
292
+ beforeRefreshDimensions: () => false,
292
293
  beforeOnCellMouseOver: (event, coords) => {
293
294
  _classPrivateFieldGet(_navigator, this).setCurrentPage(coords.row);
294
295
  },
@@ -143,7 +143,11 @@ class Positioner {
143
143
  setPositionAboveCursor() {
144
144
  let top = _classPrivateFieldGet(_offset, this).above + _classPrivateFieldGet(_cursor, this).top - _classPrivateFieldGet(_container, this).offsetHeight;
145
145
  if (_classPrivateFieldGet(_parentContainer, this)) {
146
- top = _classPrivateFieldGet(_cursor, this).top + _classPrivateFieldGet(_cursor, this).cellHeight - _classPrivateFieldGet(_container, this).offsetHeight + 3;
146
+ const rootWindow = _classPrivateFieldGet(_parentContainer, this).ownerDocument.defaultView;
147
+ const style = rootWindow.getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.ht_master'));
148
+ const paddingTop = Number.parseInt(style.paddingTop, 10);
149
+ const borderTop = Number.parseInt(style.borderTop, 10);
150
+ top = _classPrivateFieldGet(_cursor, this).top + _classPrivateFieldGet(_cursor, this).cellHeight - _classPrivateFieldGet(_container, this).scrollHeight + paddingTop + borderTop;
147
151
  }
148
152
  _classPrivateFieldGet(_container, this).style.top = `${top}px`;
149
153
  }
@@ -154,7 +158,11 @@ class Positioner {
154
158
  setPositionBelowCursor() {
155
159
  let top = _classPrivateFieldGet(_offset, this).below + _classPrivateFieldGet(_cursor, this).top + 1;
156
160
  if (_classPrivateFieldGet(_parentContainer, this)) {
157
- top = _classPrivateFieldGet(_cursor, this).top - 1;
161
+ const rootWindow = _classPrivateFieldGet(_parentContainer, this).ownerDocument.defaultView;
162
+ const style = rootWindow.getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.ht_master'));
163
+ const paddingTop = Number.parseInt(style.paddingTop, 10);
164
+ const borderTop = Number.parseInt(style.borderTop, 10);
165
+ top = _classPrivateFieldGet(_cursor, this).top - paddingTop - borderTop - 1;
158
166
  }
159
167
  _classPrivateFieldGet(_container, this).style.top = `${top}px`;
160
168
  }
@@ -140,7 +140,11 @@ export class Positioner {
140
140
  setPositionAboveCursor() {
141
141
  let top = _classPrivateFieldGet(_offset, this).above + _classPrivateFieldGet(_cursor, this).top - _classPrivateFieldGet(_container, this).offsetHeight;
142
142
  if (_classPrivateFieldGet(_parentContainer, this)) {
143
- top = _classPrivateFieldGet(_cursor, this).top + _classPrivateFieldGet(_cursor, this).cellHeight - _classPrivateFieldGet(_container, this).offsetHeight + 3;
143
+ const rootWindow = _classPrivateFieldGet(_parentContainer, this).ownerDocument.defaultView;
144
+ const style = rootWindow.getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.ht_master'));
145
+ const paddingTop = Number.parseInt(style.paddingTop, 10);
146
+ const borderTop = Number.parseInt(style.borderTop, 10);
147
+ top = _classPrivateFieldGet(_cursor, this).top + _classPrivateFieldGet(_cursor, this).cellHeight - _classPrivateFieldGet(_container, this).scrollHeight + paddingTop + borderTop;
144
148
  }
145
149
  _classPrivateFieldGet(_container, this).style.top = `${top}px`;
146
150
  }
@@ -151,7 +155,11 @@ export class Positioner {
151
155
  setPositionBelowCursor() {
152
156
  let top = _classPrivateFieldGet(_offset, this).below + _classPrivateFieldGet(_cursor, this).top + 1;
153
157
  if (_classPrivateFieldGet(_parentContainer, this)) {
154
- top = _classPrivateFieldGet(_cursor, this).top - 1;
158
+ const rootWindow = _classPrivateFieldGet(_parentContainer, this).ownerDocument.defaultView;
159
+ const style = rootWindow.getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.ht_master'));
160
+ const paddingTop = Number.parseInt(style.paddingTop, 10);
161
+ const borderTop = Number.parseInt(style.borderTop, 10);
162
+ top = _classPrivateFieldGet(_cursor, this).top - paddingTop - borderTop - 1;
155
163
  }
156
164
  _classPrivateFieldGet(_container, this).style.top = `${top}px`;
157
165
  }
@@ -256,6 +256,9 @@ class CopyPaste extends _base.BasePlugin {
256
256
  return _assertClassBrand(_CopyPaste_brand, _this, _onAfterSelection).call(_this, ...args);
257
257
  });
258
258
  this.addHook('afterSelectionEnd', () => _assertClassBrand(_CopyPaste_brand, this, _onAfterSelectionEnd).call(this));
259
+
260
+ // Events are attached to the document, not the root table element - as it should,
261
+ // for Chrome 133 and lower to copy/paste/cut work properly (#dev-2277).
259
262
  this.eventManager.addEventListener(this.hot.rootDocument, 'copy', function () {
260
263
  return _this.onCopy(...arguments);
261
264
  });
@@ -562,12 +565,10 @@ class CopyPaste extends _base.BasePlugin {
562
565
  * @private
563
566
  */
564
567
  onCopy(event) {
565
- var _event$target, _this$hot$getSelected;
568
+ const eventTarget = event.composedPath()[0];
566
569
  const focusedElement = this.hot.getFocusManager().getRefocusElement();
567
- const isHotInput = (_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.hasAttribute('data-hot-input');
568
- const selectedCell = (_this$hot$getSelected = this.hot.getSelectedRangeLast()) === null || _this$hot$getSelected === void 0 ? void 0 : _this$hot$getSelected.highlight;
569
- const TD = selectedCell ? this.hot.getCell(selectedCell.row, selectedCell.col, true) : null;
570
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || (0, _element.isHTMLElement)(event.target) && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body && TD !== event.target)) {
570
+ const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
571
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || (0, _element.isHTMLElement)(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !(0, _element.isInternalElement)(eventTarget, this.hot.rootElement))) {
571
572
  return;
572
573
  }
573
574
  event.preventDefault();
@@ -597,12 +598,10 @@ class CopyPaste extends _base.BasePlugin {
597
598
  * @private
598
599
  */
599
600
  onCut(event) {
600
- var _event$target2, _this$hot$getSelected2;
601
+ const eventTarget = event.composedPath()[0];
601
602
  const focusedElement = this.hot.getFocusManager().getRefocusElement();
602
- const isHotInput = (_event$target2 = event.target) === null || _event$target2 === void 0 ? void 0 : _event$target2.hasAttribute('data-hot-input');
603
- const selectedCell = (_this$hot$getSelected2 = this.hot.getSelectedRangeLast()) === null || _this$hot$getSelected2 === void 0 ? void 0 : _this$hot$getSelected2.highlight;
604
- const TD = selectedCell ? this.hot.getCell(selectedCell.row, selectedCell.col, true) : null;
605
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || (0, _element.isHTMLElement)(event.target) && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body && TD !== event.target)) {
603
+ const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
604
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || (0, _element.isHTMLElement)(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !(0, _element.isInternalElement)(eventTarget, this.hot.rootElement))) {
606
605
  return;
607
606
  }
608
607
  event.preventDefault();
@@ -631,12 +630,10 @@ class CopyPaste extends _base.BasePlugin {
631
630
  * @private
632
631
  */
633
632
  onPaste(event) {
634
- var _event$target3, _this$hot$getSelected3;
633
+ const eventTarget = event.composedPath()[0];
635
634
  const focusedElement = this.hot.getFocusManager().getRefocusElement();
636
- const isHotInput = (_event$target3 = event.target) === null || _event$target3 === void 0 ? void 0 : _event$target3.hasAttribute('data-hot-input');
637
- const selectedCell = (_this$hot$getSelected3 = this.hot.getSelectedRangeLast()) === null || _this$hot$getSelected3 === void 0 ? void 0 : _this$hot$getSelected3.highlight;
638
- const TD = selectedCell ? this.hot.getCell(selectedCell.row, selectedCell.col, true) : null;
639
- if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || (0, _element.isHTMLElement)(event.target) && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body && TD !== event.target)) {
635
+ const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
636
+ if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || (0, _element.isHTMLElement)(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !(0, _element.isInternalElement)(eventTarget, this.hot.rootElement))) {
640
637
  return;
641
638
  }
642
639
  event.preventDefault();
@@ -17,7 +17,7 @@ import { Hooks } from "../../core/hooks/index.mjs";
17
17
  import { stringify, parse } from "../../3rdparty/SheetClip/index.mjs";
18
18
  import { arrayEach } from "../../helpers/array.mjs";
19
19
  import { sanitize } from "../../helpers/string.mjs";
20
- import { removeContentEditableFromElementAndDeselect, runWithSelectedContendEditableElement, makeElementContentEditableAndSelectItsContent, isHTMLElement } from "../../helpers/dom/element.mjs";
20
+ import { removeContentEditableFromElementAndDeselect, runWithSelectedContendEditableElement, makeElementContentEditableAndSelectItsContent, isHTMLElement, isInternalElement } from "../../helpers/dom/element.mjs";
21
21
  import { isSafari } from "../../helpers/browser.mjs";
22
22
  import copyItem from "./contextMenuItem/copy.mjs";
23
23
  import copyColumnHeadersOnlyItem from "./contextMenuItem/copyColumnHeadersOnly.mjs";
@@ -252,6 +252,9 @@ export class CopyPaste extends BasePlugin {
252
252
  return _assertClassBrand(_CopyPaste_brand, _this, _onAfterSelection).call(_this, ...args);
253
253
  });
254
254
  this.addHook('afterSelectionEnd', () => _assertClassBrand(_CopyPaste_brand, this, _onAfterSelectionEnd).call(this));
255
+
256
+ // Events are attached to the document, not the root table element - as it should,
257
+ // for Chrome 133 and lower to copy/paste/cut work properly (#dev-2277).
255
258
  this.eventManager.addEventListener(this.hot.rootDocument, 'copy', function () {
256
259
  return _this.onCopy(...arguments);
257
260
  });
@@ -558,12 +561,10 @@ export class CopyPaste extends BasePlugin {
558
561
  * @private
559
562
  */
560
563
  onCopy(event) {
561
- var _event$target, _this$hot$getSelected;
564
+ const eventTarget = event.composedPath()[0];
562
565
  const focusedElement = this.hot.getFocusManager().getRefocusElement();
563
- const isHotInput = (_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.hasAttribute('data-hot-input');
564
- const selectedCell = (_this$hot$getSelected = this.hot.getSelectedRangeLast()) === null || _this$hot$getSelected === void 0 ? void 0 : _this$hot$getSelected.highlight;
565
- const TD = selectedCell ? this.hot.getCell(selectedCell.row, selectedCell.col, true) : null;
566
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || isHTMLElement(event.target) && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body && TD !== event.target)) {
566
+ const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
567
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || isHTMLElement(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !isInternalElement(eventTarget, this.hot.rootElement))) {
567
568
  return;
568
569
  }
569
570
  event.preventDefault();
@@ -593,12 +594,10 @@ export class CopyPaste extends BasePlugin {
593
594
  * @private
594
595
  */
595
596
  onCut(event) {
596
- var _event$target2, _this$hot$getSelected2;
597
+ const eventTarget = event.composedPath()[0];
597
598
  const focusedElement = this.hot.getFocusManager().getRefocusElement();
598
- const isHotInput = (_event$target2 = event.target) === null || _event$target2 === void 0 ? void 0 : _event$target2.hasAttribute('data-hot-input');
599
- const selectedCell = (_this$hot$getSelected2 = this.hot.getSelectedRangeLast()) === null || _this$hot$getSelected2 === void 0 ? void 0 : _this$hot$getSelected2.highlight;
600
- const TD = selectedCell ? this.hot.getCell(selectedCell.row, selectedCell.col, true) : null;
601
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || isHTMLElement(event.target) && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body && TD !== event.target)) {
599
+ const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
600
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || isHTMLElement(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !isInternalElement(eventTarget, this.hot.rootElement))) {
602
601
  return;
603
602
  }
604
603
  event.preventDefault();
@@ -627,12 +626,10 @@ export class CopyPaste extends BasePlugin {
627
626
  * @private
628
627
  */
629
628
  onPaste(event) {
630
- var _event$target3, _this$hot$getSelected3;
629
+ const eventTarget = event.composedPath()[0];
631
630
  const focusedElement = this.hot.getFocusManager().getRefocusElement();
632
- const isHotInput = (_event$target3 = event.target) === null || _event$target3 === void 0 ? void 0 : _event$target3.hasAttribute('data-hot-input');
633
- const selectedCell = (_this$hot$getSelected3 = this.hot.getSelectedRangeLast()) === null || _this$hot$getSelected3 === void 0 ? void 0 : _this$hot$getSelected3.highlight;
634
- const TD = selectedCell ? this.hot.getCell(selectedCell.row, selectedCell.col, true) : null;
635
- if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || isHTMLElement(event.target) && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body && TD !== event.target)) {
631
+ const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
632
+ if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || isHTMLElement(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !isInternalElement(eventTarget, this.hot.rootElement))) {
636
633
  return;
637
634
  }
638
635
  event.preventDefault();
@@ -11,5 +11,8 @@ class PasteEvent {
11
11
  this.clipboardData = new _clipboardData.default();
12
12
  }
13
13
  preventDefault() {}
14
+ composedPath() {
15
+ return [];
16
+ }
14
17
  }
15
18
  exports.default = PasteEvent;
@@ -7,4 +7,7 @@ export default class PasteEvent {
7
7
  this.clipboardData = new ClipboardData();
8
8
  }
9
9
  preventDefault() {}
10
+ composedPath() {
11
+ return [];
12
+ }
10
13
  }
@@ -80,6 +80,21 @@ const SHORTCUTS_GROUP = PLUGIN_KEY;
80
80
  * />
81
81
  * ```
82
82
  * :::
83
+ *
84
+ * ::: only-for angular
85
+ * ```ts
86
+ * settings = {
87
+ * data: data,
88
+ * comments: true,
89
+ * // enable and configure dropdown menu
90
+ * dropdownMenu: ["remove_col", "---------", "make_read_only", "alignment"],
91
+ * };
92
+ * ```
93
+ *
94
+ * ```html
95
+ * <hot-table [settings]="settings"></hot-table>
96
+ * ```
97
+ * :::
83
98
  */
84
99
  var _isButtonClicked = /*#__PURE__*/new WeakMap();
85
100
  var _DropdownMenu_brand = /*#__PURE__*/new WeakSet();
@@ -77,6 +77,21 @@ const SHORTCUTS_GROUP = PLUGIN_KEY;
77
77
  * />
78
78
  * ```
79
79
  * :::
80
+ *
81
+ * ::: only-for angular
82
+ * ```ts
83
+ * settings = {
84
+ * data: data,
85
+ * comments: true,
86
+ * // enable and configure dropdown menu
87
+ * dropdownMenu: ["remove_col", "---------", "make_read_only", "alignment"],
88
+ * };
89
+ * ```
90
+ *
91
+ * ```html
92
+ * <hot-table [settings]="settings"></hot-table>
93
+ * ```
94
+ * :::
80
95
  */
81
96
  var _isButtonClicked = /*#__PURE__*/new WeakMap();
82
97
  var _DropdownMenu_brand = /*#__PURE__*/new WeakSet();
@@ -87,6 +87,64 @@ const PLUGIN_PRIORITY = exports.PLUGIN_PRIORITY = 240;
87
87
  * });
88
88
  * ```
89
89
  * :::
90
+ *
91
+ * ::: only-for angular
92
+ * ```ts
93
+ * import { AfterViewInit, Component, ViewChild } from "@angular/core";
94
+ * import {
95
+ * GridSettings,
96
+ * HotTableModule,
97
+ * HotTableComponent,
98
+ * } from "@handsontable/angular-wrapper";
99
+ *
100
+ * `@Component`({
101
+ * selector: "app-example",
102
+ * standalone: true,
103
+ * imports: [HotTableModule],
104
+ * template: ` <div class="ht-theme-main">
105
+ * <hot-table [settings]="gridSettings" />
106
+ * </div>`,
107
+ * })
108
+ * export class ExampleComponent implements AfterViewInit {
109
+ * `@ViewChild`(HotTableComponent, { static: false })
110
+ * readonly hotTable!: HotTableComponent;
111
+ *
112
+ * readonly gridSettings = <GridSettings>{
113
+ * data: this.getData(),
114
+ * };
115
+ *
116
+ * ngAfterViewInit(): void {
117
+ * // Access to plugin instance:
118
+ * const hot = this.hotTable.hotInstance;
119
+ * // Access to exportFile plugin instance
120
+ * const exportPlugin = hot.getPlugin("exportFile");
121
+ *
122
+ * // Export as a string
123
+ * exportPlugin.exportAsString("csv");
124
+ *
125
+ * // Export as a blob object
126
+ * exportPlugin.exportAsBlob("csv");
127
+ *
128
+ * // Export to downloadable file (named: MyFile.csv)
129
+ * exportPlugin.downloadFile("csv", { filename: "MyFile" });
130
+ *
131
+ * // Export as a string (with specified data range):
132
+ * exportPlugin.exportAsString("csv", {
133
+ * exportHiddenRows: true, // default false
134
+ * exportHiddenColumns: true, // default false
135
+ * columnHeaders: true, // default false
136
+ * rowHeaders: true, // default false
137
+ * columnDelimiter: ";", // default ','
138
+ * range: [1, 1, 6, 6], // [startRow, endRow, startColumn, endColumn]
139
+ * });
140
+ * }
141
+ *
142
+ * private getData(): any[] {
143
+ * // get some data
144
+ * }
145
+ * }
146
+ * ```
147
+ * :::
90
148
  */
91
149
  class ExportFile extends _base.BasePlugin {
92
150
  static get PLUGIN_KEY() {