handsontable 14.5.0 → 14.6.0-next-4d69faf-20240924

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 (124) hide show
  1. package/3rdparty/walkontable/src/renderer/rows.js +10 -0
  2. package/3rdparty/walkontable/src/renderer/rows.mjs +11 -1
  3. package/3rdparty/walkontable/src/selection/manager.js +7 -7
  4. package/3rdparty/walkontable/src/selection/manager.mjs +7 -7
  5. package/3rdparty/walkontable/src/selection/scanner.js +7 -7
  6. package/3rdparty/walkontable/src/selection/scanner.mjs +7 -7
  7. package/CHANGELOG.md +29 -0
  8. package/base.js +2 -2
  9. package/base.mjs +2 -2
  10. package/core.d.ts +13 -2
  11. package/core.js +160 -9
  12. package/core.mjs +160 -9
  13. package/dataMap/metaManager/lazyFactoryMap.js +7 -7
  14. package/dataMap/metaManager/lazyFactoryMap.mjs +7 -7
  15. package/dataMap/metaManager/metaSchema.js +5 -6
  16. package/dataMap/metaManager/metaSchema.mjs +7 -8
  17. package/dataMap/metaManager/mods/dynamicCellMeta.js +7 -7
  18. package/dataMap/metaManager/mods/dynamicCellMeta.mjs +7 -7
  19. package/dataMap/metaManager/mods/extendMetaProperties.js +7 -7
  20. package/dataMap/metaManager/mods/extendMetaProperties.mjs +7 -7
  21. package/dataMap/metaManager/utils.js +7 -7
  22. package/dataMap/metaManager/utils.mjs +7 -7
  23. package/dist/handsontable.css +3 -17
  24. package/dist/handsontable.full.css +3 -17
  25. package/dist/handsontable.full.js +3498 -3219
  26. package/dist/handsontable.full.min.css +3 -3
  27. package/dist/handsontable.full.min.js +109 -119
  28. package/dist/handsontable.js +3172 -2897
  29. package/dist/handsontable.min.css +3 -3
  30. package/dist/handsontable.min.js +19 -19
  31. package/editors/autocompleteEditor/autocompleteEditor.d.ts +1 -1
  32. package/helpers/a11y.js +2 -0
  33. package/helpers/a11y.mjs +1 -0
  34. package/helpers/array.js +7 -7
  35. package/helpers/array.mjs +7 -7
  36. package/helpers/mixed.js +2 -2
  37. package/helpers/mixed.mjs +2 -2
  38. package/helpers/number.js +7 -7
  39. package/helpers/number.mjs +7 -7
  40. package/package.json +1 -1
  41. package/pluginHooks.d.ts +1 -1
  42. package/pluginHooks.js +1 -0
  43. package/pluginHooks.mjs +1 -0
  44. package/plugins/autoRowSize/autoRowSize.js +1 -2
  45. package/plugins/autoRowSize/autoRowSize.mjs +1 -2
  46. package/plugins/columnSorting/columnSorting.js +10 -1
  47. package/plugins/columnSorting/columnSorting.mjs +10 -1
  48. package/plugins/columnSorting/utils.js +7 -7
  49. package/plugins/columnSorting/utils.mjs +7 -7
  50. package/plugins/contextMenu/contextMenu.js +7 -0
  51. package/plugins/contextMenu/contextMenu.mjs +7 -0
  52. package/plugins/contextMenu/menu/menu.js +47 -14
  53. package/plugins/contextMenu/menu/menu.mjs +48 -15
  54. package/plugins/contextMenu/menu/menuItemRenderer.js +3 -4
  55. package/plugins/contextMenu/menu/menuItemRenderer.mjs +5 -6
  56. package/plugins/contextMenu/menu/positioner.js +4 -12
  57. package/plugins/contextMenu/menu/positioner.mjs +4 -12
  58. package/plugins/contextMenu/menu/utils.js +11 -0
  59. package/plugins/contextMenu/menu/utils.mjs +10 -0
  60. package/plugins/contextMenu/predefinedItems/alignment.js +56 -49
  61. package/plugins/contextMenu/predefinedItems/alignment.mjs +57 -50
  62. package/plugins/contextMenu/predefinedItems/readOnly.js +8 -0
  63. package/plugins/contextMenu/predefinedItems/readOnly.mjs +8 -0
  64. package/plugins/contextMenu/utils.js +26 -0
  65. package/plugins/contextMenu/utils.mjs +24 -0
  66. package/plugins/copyPaste/copyPaste.js +14 -14
  67. package/plugins/copyPaste/copyPaste.mjs +14 -14
  68. package/plugins/dropdownMenu/dropdownMenu.js +10 -4
  69. package/plugins/dropdownMenu/dropdownMenu.mjs +10 -4
  70. package/plugins/filters/component/condition.js +6 -1
  71. package/plugins/filters/component/condition.mjs +6 -1
  72. package/plugins/filters/component/value.js +6 -1
  73. package/plugins/filters/component/value.mjs +6 -1
  74. package/plugins/filters/conditionCollection.d.ts +4 -3
  75. package/plugins/filters/conditionCollection.js +26 -0
  76. package/plugins/filters/conditionCollection.mjs +26 -0
  77. package/plugins/filters/filters.js +4 -1
  78. package/plugins/filters/filters.mjs +4 -1
  79. package/plugins/filters/ui/multipleSelect.js +7 -9
  80. package/plugins/filters/ui/multipleSelect.mjs +7 -9
  81. package/plugins/filters/utils.js +7 -7
  82. package/plugins/filters/utils.mjs +7 -7
  83. package/plugins/formulas/formulas.js +7 -7
  84. package/plugins/formulas/formulas.mjs +7 -7
  85. package/plugins/hiddenColumns/hiddenColumns.js +7 -7
  86. package/plugins/hiddenColumns/hiddenColumns.mjs +7 -7
  87. package/plugins/hiddenRows/hiddenRows.js +7 -7
  88. package/plugins/hiddenRows/hiddenRows.mjs +7 -7
  89. package/plugins/mergeCells/cellsCollection.js +18 -16
  90. package/plugins/mergeCells/cellsCollection.mjs +19 -17
  91. package/plugins/mergeCells/mergeCells.js +7 -7
  92. package/plugins/mergeCells/mergeCells.mjs +7 -7
  93. package/plugins/nestedHeaders/stateManager/nodeModifiers/collapse.js +7 -7
  94. package/plugins/nestedHeaders/stateManager/nodeModifiers/collapse.mjs +7 -7
  95. package/plugins/nestedHeaders/stateManager/nodeModifiers/expand.js +7 -7
  96. package/plugins/nestedHeaders/stateManager/nodeModifiers/expand.mjs +7 -7
  97. package/plugins/nestedRows/nestedRows.js +7 -7
  98. package/plugins/nestedRows/nestedRows.mjs +7 -7
  99. package/plugins/trimRows/trimRows.js +7 -7
  100. package/plugins/trimRows/trimRows.mjs +7 -7
  101. package/plugins/undoRedo/undoRedo.js +9 -5
  102. package/plugins/undoRedo/undoRedo.mjs +9 -5
  103. package/renderers/checkboxRenderer/checkboxRenderer.js +18 -6
  104. package/renderers/checkboxRenderer/checkboxRenderer.mjs +18 -6
  105. package/selection/selection.js +7 -7
  106. package/selection/selection.mjs +7 -7
  107. package/selection/utils.js +7 -7
  108. package/selection/utils.mjs +7 -7
  109. package/shortcutContexts/grid.js +10 -3
  110. package/shortcutContexts/grid.mjs +10 -3
  111. package/shortcuts/keyObserver.js +7 -7
  112. package/shortcuts/keyObserver.mjs +7 -7
  113. package/shortcuts/utils.js +3 -1
  114. package/shortcuts/utils.mjs +3 -1
  115. package/translations/changesObservable/observable.js +7 -7
  116. package/translations/changesObservable/observable.mjs +7 -7
  117. package/translations/indexMapper.js +7 -7
  118. package/translations/indexMapper.mjs +7 -7
  119. package/utils/dataStructures/uniqueSet.js +7 -7
  120. package/utils/dataStructures/uniqueSet.mjs +7 -7
  121. package/utils/ghostTable.js +11 -9
  122. package/utils/ghostTable.mjs +12 -10
  123. package/utils/paginator.js +7 -7
  124. package/utils/paginator.mjs +7 -7
@@ -4,6 +4,7 @@ exports.__esModule = true;
4
4
  exports.filterSeparators = filterSeparators;
5
5
  exports.hasSubMenu = hasSubMenu;
6
6
  exports.isDisabled = isDisabled;
7
+ exports.isItemCheckable = isItemCheckable;
7
8
  exports.isItemDisabled = isItemDisabled;
8
9
  exports.isItemHidden = isItemHidden;
9
10
  exports.isItemSelectionDisabled = isItemSelectionDisabled;
@@ -174,4 +175,14 @@ function filterSeparators(items) {
174
175
  result = popSeparators(result, separator);
175
176
  result = removeDuplicatedSeparators(result);
176
177
  return result;
178
+ }
179
+
180
+ /**
181
+ * Check if the provided element presents the checkboxable menu item.
182
+ *
183
+ * @param {object} itemToTest Item element.
184
+ * @returns {boolean}
185
+ */
186
+ function isItemCheckable(itemToTest) {
187
+ return itemToTest.checkable === true;
177
188
  }
@@ -160,4 +160,14 @@ export function filterSeparators(items) {
160
160
  result = popSeparators(result, separator);
161
161
  result = removeDuplicatedSeparators(result);
162
162
  return result;
163
+ }
164
+
165
+ /**
166
+ * Check if the provided element presents the checkboxable menu item.
167
+ *
168
+ * @param {object} itemToTest Item element.
169
+ * @returns {boolean}
170
+ */
171
+ export function isItemCheckable(itemToTest) {
172
+ return itemToTest.checkable === true;
163
173
  }
@@ -34,15 +34,16 @@ function alignmentItem() {
34
34
  submenu: {
35
35
  items: [{
36
36
  key: `${KEY}:left`,
37
+ checkable: true,
38
+ ariaLabel() {
39
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
40
+ },
41
+ ariaChecked() {
42
+ return (0, _utils.hasSelectionAClass)(this, 'htLeft');
43
+ },
37
44
  name() {
38
45
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
39
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
40
- const className = this.getCellMeta(row, col).className;
41
- if (className && className.indexOf('htLeft') !== -1) {
42
- return true;
43
- }
44
- });
45
- if (hasClass) {
46
+ if ((0, _utils.hasSelectionAClass)(this, 'htLeft')) {
46
47
  label = (0, _utils.markLabelAsSelected)(label);
47
48
  }
48
49
  return label;
@@ -59,15 +60,16 @@ function alignmentItem() {
59
60
  disabled: false
60
61
  }, {
61
62
  key: `${KEY}:center`,
63
+ checkable: true,
64
+ ariaLabel() {
65
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
66
+ },
67
+ ariaChecked() {
68
+ return (0, _utils.hasSelectionAClass)(this, 'htCenter');
69
+ },
62
70
  name() {
63
71
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
64
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
65
- const className = this.getCellMeta(row, col).className;
66
- if (className && className.indexOf('htCenter') !== -1) {
67
- return true;
68
- }
69
- });
70
- if (hasClass) {
72
+ if ((0, _utils.hasSelectionAClass)(this, 'htCenter')) {
71
73
  label = (0, _utils.markLabelAsSelected)(label);
72
74
  }
73
75
  return label;
@@ -84,15 +86,16 @@ function alignmentItem() {
84
86
  disabled: false
85
87
  }, {
86
88
  key: `${KEY}:right`,
89
+ checkable: true,
90
+ ariaLabel() {
91
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
92
+ },
93
+ ariaChecked() {
94
+ return (0, _utils.hasSelectionAClass)(this, 'htRight');
95
+ },
87
96
  name() {
88
97
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
89
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
90
- const className = this.getCellMeta(row, col).className;
91
- if (className && className.indexOf('htRight') !== -1) {
92
- return true;
93
- }
94
- });
95
- if (hasClass) {
98
+ if ((0, _utils.hasSelectionAClass)(this, 'htRight')) {
96
99
  label = (0, _utils.markLabelAsSelected)(label);
97
100
  }
98
101
  return label;
@@ -109,15 +112,16 @@ function alignmentItem() {
109
112
  disabled: false
110
113
  }, {
111
114
  key: `${KEY}:justify`,
115
+ checkable: true,
116
+ ariaLabel() {
117
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
118
+ },
119
+ ariaChecked() {
120
+ return (0, _utils.hasSelectionAClass)(this, 'htJustify');
121
+ },
112
122
  name() {
113
123
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
114
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
115
- const className = this.getCellMeta(row, col).className;
116
- if (className && className.indexOf('htJustify') !== -1) {
117
- return true;
118
- }
119
- });
120
- if (hasClass) {
124
+ if ((0, _utils.hasSelectionAClass)(this, 'htJustify')) {
121
125
  label = (0, _utils.markLabelAsSelected)(label);
122
126
  }
123
127
  return label;
@@ -136,15 +140,16 @@ function alignmentItem() {
136
140
  name: _separator.KEY
137
141
  }, {
138
142
  key: `${KEY}:top`,
143
+ checkable: true,
144
+ ariaLabel() {
145
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
146
+ },
147
+ ariaChecked() {
148
+ return (0, _utils.hasSelectionAClass)(this, 'htTop');
149
+ },
139
150
  name() {
140
151
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
141
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
142
- const className = this.getCellMeta(row, col).className;
143
- if (className && className.indexOf('htTop') !== -1) {
144
- return true;
145
- }
146
- });
147
- if (hasClass) {
152
+ if ((0, _utils.hasSelectionAClass)(this, 'htTop')) {
148
153
  label = (0, _utils.markLabelAsSelected)(label);
149
154
  }
150
155
  return label;
@@ -161,15 +166,16 @@ function alignmentItem() {
161
166
  disabled: false
162
167
  }, {
163
168
  key: `${KEY}:middle`,
169
+ checkable: true,
170
+ ariaLabel() {
171
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
172
+ },
173
+ ariaChecked() {
174
+ return (0, _utils.hasSelectionAClass)(this, 'htMiddle');
175
+ },
164
176
  name() {
165
177
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
166
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
167
- const className = this.getCellMeta(row, col).className;
168
- if (className && className.indexOf('htMiddle') !== -1) {
169
- return true;
170
- }
171
- });
172
- if (hasClass) {
178
+ if ((0, _utils.hasSelectionAClass)(this, 'htMiddle')) {
173
179
  label = (0, _utils.markLabelAsSelected)(label);
174
180
  }
175
181
  return label;
@@ -186,15 +192,16 @@ function alignmentItem() {
186
192
  disabled: false
187
193
  }, {
188
194
  key: `${KEY}:bottom`,
195
+ checkable: true,
196
+ ariaLabel() {
197
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
198
+ },
199
+ ariaChecked() {
200
+ return (0, _utils.hasSelectionAClass)(this, 'htBottom');
201
+ },
189
202
  name() {
190
203
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
191
- const hasClass = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => {
192
- const className = this.getCellMeta(row, col).className;
193
- if (className && className.indexOf('htBottom') !== -1) {
194
- return true;
195
- }
196
- });
197
- if (hasClass) {
204
+ if ((0, _utils.hasSelectionAClass)(this, 'htBottom')) {
198
205
  label = (0, _utils.markLabelAsSelected)(label);
199
206
  }
200
207
  return label;
@@ -1,4 +1,4 @@
1
- import { align, getAlignmentClasses, checkSelectionConsistency, markLabelAsSelected } from "../utils.mjs";
1
+ import { align, getAlignmentClasses, markLabelAsSelected, hasSelectionAClass } from "../utils.mjs";
2
2
  import { KEY as SEPARATOR } from "./separator.mjs";
3
3
  import * as C from "../../../i18n/constants.mjs";
4
4
  export const KEY = 'alignment';
@@ -28,15 +28,16 @@ export default function alignmentItem() {
28
28
  submenu: {
29
29
  items: [{
30
30
  key: `${KEY}:left`,
31
+ checkable: true,
32
+ ariaLabel() {
33
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
34
+ },
35
+ ariaChecked() {
36
+ return hasSelectionAClass(this, 'htLeft');
37
+ },
31
38
  name() {
32
39
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
33
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
34
- const className = this.getCellMeta(row, col).className;
35
- if (className && className.indexOf('htLeft') !== -1) {
36
- return true;
37
- }
38
- });
39
- if (hasClass) {
40
+ if (hasSelectionAClass(this, 'htLeft')) {
40
41
  label = markLabelAsSelected(label);
41
42
  }
42
43
  return label;
@@ -53,15 +54,16 @@ export default function alignmentItem() {
53
54
  disabled: false
54
55
  }, {
55
56
  key: `${KEY}:center`,
57
+ checkable: true,
58
+ ariaLabel() {
59
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
60
+ },
61
+ ariaChecked() {
62
+ return hasSelectionAClass(this, 'htCenter');
63
+ },
56
64
  name() {
57
65
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
58
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
59
- const className = this.getCellMeta(row, col).className;
60
- if (className && className.indexOf('htCenter') !== -1) {
61
- return true;
62
- }
63
- });
64
- if (hasClass) {
66
+ if (hasSelectionAClass(this, 'htCenter')) {
65
67
  label = markLabelAsSelected(label);
66
68
  }
67
69
  return label;
@@ -78,15 +80,16 @@ export default function alignmentItem() {
78
80
  disabled: false
79
81
  }, {
80
82
  key: `${KEY}:right`,
83
+ checkable: true,
84
+ ariaLabel() {
85
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
86
+ },
87
+ ariaChecked() {
88
+ return hasSelectionAClass(this, 'htRight');
89
+ },
81
90
  name() {
82
91
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
83
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
84
- const className = this.getCellMeta(row, col).className;
85
- if (className && className.indexOf('htRight') !== -1) {
86
- return true;
87
- }
88
- });
89
- if (hasClass) {
92
+ if (hasSelectionAClass(this, 'htRight')) {
90
93
  label = markLabelAsSelected(label);
91
94
  }
92
95
  return label;
@@ -103,15 +106,16 @@ export default function alignmentItem() {
103
106
  disabled: false
104
107
  }, {
105
108
  key: `${KEY}:justify`,
109
+ checkable: true,
110
+ ariaLabel() {
111
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
112
+ },
113
+ ariaChecked() {
114
+ return hasSelectionAClass(this, 'htJustify');
115
+ },
106
116
  name() {
107
117
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
108
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
109
- const className = this.getCellMeta(row, col).className;
110
- if (className && className.indexOf('htJustify') !== -1) {
111
- return true;
112
- }
113
- });
114
- if (hasClass) {
118
+ if (hasSelectionAClass(this, 'htJustify')) {
115
119
  label = markLabelAsSelected(label);
116
120
  }
117
121
  return label;
@@ -130,15 +134,16 @@ export default function alignmentItem() {
130
134
  name: SEPARATOR
131
135
  }, {
132
136
  key: `${KEY}:top`,
137
+ checkable: true,
138
+ ariaLabel() {
139
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
140
+ },
141
+ ariaChecked() {
142
+ return hasSelectionAClass(this, 'htTop');
143
+ },
133
144
  name() {
134
145
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
135
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
136
- const className = this.getCellMeta(row, col).className;
137
- if (className && className.indexOf('htTop') !== -1) {
138
- return true;
139
- }
140
- });
141
- if (hasClass) {
146
+ if (hasSelectionAClass(this, 'htTop')) {
142
147
  label = markLabelAsSelected(label);
143
148
  }
144
149
  return label;
@@ -155,15 +160,16 @@ export default function alignmentItem() {
155
160
  disabled: false
156
161
  }, {
157
162
  key: `${KEY}:middle`,
163
+ checkable: true,
164
+ ariaLabel() {
165
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
166
+ },
167
+ ariaChecked() {
168
+ return hasSelectionAClass(this, 'htMiddle');
169
+ },
158
170
  name() {
159
171
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
160
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
161
- const className = this.getCellMeta(row, col).className;
162
- if (className && className.indexOf('htMiddle') !== -1) {
163
- return true;
164
- }
165
- });
166
- if (hasClass) {
172
+ if (hasSelectionAClass(this, 'htMiddle')) {
167
173
  label = markLabelAsSelected(label);
168
174
  }
169
175
  return label;
@@ -180,15 +186,16 @@ export default function alignmentItem() {
180
186
  disabled: false
181
187
  }, {
182
188
  key: `${KEY}:bottom`,
189
+ checkable: true,
190
+ ariaLabel() {
191
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
192
+ },
193
+ ariaChecked() {
194
+ return hasSelectionAClass(this, 'htBottom');
195
+ },
183
196
  name() {
184
197
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
185
- const hasClass = checkSelectionConsistency(this.getSelectedRange(), (row, col) => {
186
- const className = this.getCellMeta(row, col).className;
187
- if (className && className.indexOf('htBottom') !== -1) {
188
- return true;
189
- }
190
- });
191
- if (hasClass) {
198
+ if (hasSelectionAClass(this, 'htBottom')) {
192
199
  label = markLabelAsSelected(label);
193
200
  }
194
201
  return label;
@@ -15,6 +15,14 @@ const KEY = exports.KEY = 'make_read_only';
15
15
  function readOnlyItem() {
16
16
  return {
17
17
  key: KEY,
18
+ checkable: true,
19
+ ariaChecked() {
20
+ const atLeastOneReadOnly = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => this.getCellMeta(row, col).readOnly);
21
+ return atLeastOneReadOnly;
22
+ },
23
+ ariaLabel() {
24
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_READ_ONLY);
25
+ },
18
26
  name() {
19
27
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_READ_ONLY);
20
28
  const atLeastOneReadOnly = (0, _utils.checkSelectionConsistency)(this.getSelectedRange(), (row, col) => this.getCellMeta(row, col).readOnly);
@@ -9,6 +9,14 @@ export const KEY = 'make_read_only';
9
9
  export default function readOnlyItem() {
10
10
  return {
11
11
  key: KEY,
12
+ checkable: true,
13
+ ariaChecked() {
14
+ const atLeastOneReadOnly = checkSelectionConsistency(this.getSelectedRange(), (row, col) => this.getCellMeta(row, col).readOnly);
15
+ return atLeastOneReadOnly;
16
+ },
17
+ ariaLabel() {
18
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_READ_ONLY);
19
+ },
12
20
  name() {
13
21
  let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_READ_ONLY);
14
22
  const atLeastOneReadOnly = checkSelectionConsistency(this.getSelectedRange(), (row, col) => this.getCellMeta(row, col).readOnly);
@@ -4,7 +4,9 @@ exports.__esModule = true;
4
4
  exports.align = align;
5
5
  exports.checkSelectionConsistency = checkSelectionConsistency;
6
6
  exports.getAlignmentClasses = getAlignmentClasses;
7
+ exports.getAlignmentComparatorByClass = getAlignmentComparatorByClass;
7
8
  exports.getDocumentOffsetByElement = getDocumentOffsetByElement;
9
+ exports.hasSelectionAClass = hasSelectionAClass;
8
10
  exports.markLabelAsSelected = markLabelAsSelected;
9
11
  exports.prepareHorizontalAlignClass = prepareHorizontalAlignClass;
10
12
  exports.prepareVerticalAlignClass = prepareVerticalAlignClass;
@@ -151,4 +153,28 @@ function getDocumentOffsetByElement(elementToCheck, baseDocument) {
151
153
  offset.left = left;
152
154
  }
153
155
  return offset;
156
+ }
157
+
158
+ /**
159
+ * Prepares comparator function consumable by checkSelectionConsistency
160
+ * Comparator function checks if the cell has the provided class name.
161
+ *
162
+ * @param {string} htClassName The class name to check.
163
+ * @returns {Function} Returns the comparator function.
164
+ * Use with .bind, .call or .apply to pass the Handsontable instance.
165
+ */
166
+ function getAlignmentComparatorByClass(htClassName) {
167
+ return function (row, col) {
168
+ const className = this.getCellMeta(row, col).className;
169
+ return className && className.indexOf(htClassName) !== -1;
170
+ };
171
+ }
172
+
173
+ /**
174
+ * @param {object} hot Handsontable instance.
175
+ * @param {string} htClassName The class name to check.
176
+ * @returns {boolean} Returns true if at least one cell has the provided class name.
177
+ */
178
+ function hasSelectionAClass(hot, htClassName) {
179
+ return checkSelectionConsistency(hot.getSelectedRange(), getAlignmentComparatorByClass(htClassName).bind(hot));
154
180
  }
@@ -141,4 +141,28 @@ export function getDocumentOffsetByElement(elementToCheck, baseDocument) {
141
141
  offset.left = left;
142
142
  }
143
143
  return offset;
144
+ }
145
+
146
+ /**
147
+ * Prepares comparator function consumable by checkSelectionConsistency
148
+ * Comparator function checks if the cell has the provided class name.
149
+ *
150
+ * @param {string} htClassName The class name to check.
151
+ * @returns {Function} Returns the comparator function.
152
+ * Use with .bind, .call or .apply to pass the Handsontable instance.
153
+ */
154
+ export function getAlignmentComparatorByClass(htClassName) {
155
+ return function (row, col) {
156
+ const className = this.getCellMeta(row, col).className;
157
+ return className && className.indexOf(htClassName) !== -1;
158
+ };
159
+ }
160
+
161
+ /**
162
+ * @param {object} hot Handsontable instance.
163
+ * @param {string} htClassName The class name to check.
164
+ * @returns {boolean} Returns true if at least one cell has the provided class name.
165
+ */
166
+ export function hasSelectionAClass(hot, htClassName) {
167
+ return checkSelectionConsistency(hot.getSelectedRange(), getAlignmentComparatorByClass(htClassName).bind(hot));
144
168
  }
@@ -553,12 +553,13 @@ class CopyPaste extends _base.BasePlugin {
553
553
  * @private
554
554
  */
555
555
  onCopy(event) {
556
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened()) {
557
- return;
558
- }
559
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
556
+ var _event$target;
557
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
558
+ const isHotInput = (_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.hasAttribute('data-hot-input');
559
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
560
560
  return;
561
561
  }
562
+ event.preventDefault();
562
563
  this.setCopyableText();
563
564
  _classPrivateFieldSet(_isTriggeredByCopy, this, false);
564
565
  const data = this.getRangedData(this.copyableRanges);
@@ -576,7 +577,6 @@ class CopyPaste extends _base.BasePlugin {
576
577
  this.hot.runHooks('afterCopy', data, this.copyableRanges, copiedHeadersCount);
577
578
  }
578
579
  _classPrivateFieldSet(_copyMode, this, 'cells-only');
579
- event.preventDefault();
580
580
  }
581
581
 
582
582
  /**
@@ -586,12 +586,13 @@ class CopyPaste extends _base.BasePlugin {
586
586
  * @private
587
587
  */
588
588
  onCut(event) {
589
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened()) {
590
- return;
591
- }
592
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
589
+ var _event$target2;
590
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
591
+ const isHotInput = (_event$target2 = event.target) === null || _event$target2 === void 0 ? void 0 : _event$target2.hasAttribute('data-hot-input');
592
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
593
593
  return;
594
594
  }
595
+ event.preventDefault();
595
596
  this.setCopyableText();
596
597
  _classPrivateFieldSet(_isTriggeredByCut, this, false);
597
598
  const rangedData = this.getRangedData(this.copyableRanges);
@@ -608,7 +609,6 @@ class CopyPaste extends _base.BasePlugin {
608
609
  this.hot.emptySelectedCells('CopyPaste.cut');
609
610
  this.hot.runHooks('afterCut', rangedData, this.copyableRanges);
610
611
  }
611
- event.preventDefault();
612
612
  }
613
613
 
614
614
  /**
@@ -618,10 +618,10 @@ class CopyPaste extends _base.BasePlugin {
618
618
  * @private
619
619
  */
620
620
  onPaste(event) {
621
- if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected()) {
622
- return;
623
- }
624
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
621
+ var _event$target3;
622
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
623
+ const isHotInput = (_event$target3 = event.target) === null || _event$target3 === void 0 ? void 0 : _event$target3.hasAttribute('data-hot-input');
624
+ if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
625
625
  return;
626
626
  }
627
627
  event.preventDefault();
@@ -549,12 +549,13 @@ export class CopyPaste extends BasePlugin {
549
549
  * @private
550
550
  */
551
551
  onCopy(event) {
552
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened()) {
553
- return;
554
- }
555
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
552
+ var _event$target;
553
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
554
+ const isHotInput = (_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.hasAttribute('data-hot-input');
555
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
556
556
  return;
557
557
  }
558
+ event.preventDefault();
558
559
  this.setCopyableText();
559
560
  _classPrivateFieldSet(_isTriggeredByCopy, this, false);
560
561
  const data = this.getRangedData(this.copyableRanges);
@@ -572,7 +573,6 @@ export class CopyPaste extends BasePlugin {
572
573
  this.hot.runHooks('afterCopy', data, this.copyableRanges, copiedHeadersCount);
573
574
  }
574
575
  _classPrivateFieldSet(_copyMode, this, 'cells-only');
575
- event.preventDefault();
576
576
  }
577
577
 
578
578
  /**
@@ -582,12 +582,13 @@ export class CopyPaste extends BasePlugin {
582
582
  * @private
583
583
  */
584
584
  onCut(event) {
585
- if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened()) {
586
- return;
587
- }
588
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
585
+ var _event$target2;
586
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
587
+ const isHotInput = (_event$target2 = event.target) === null || _event$target2 === void 0 ? void 0 : _event$target2.hasAttribute('data-hot-input');
588
+ if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
589
589
  return;
590
590
  }
591
+ event.preventDefault();
591
592
  this.setCopyableText();
592
593
  _classPrivateFieldSet(_isTriggeredByCut, this, false);
593
594
  const rangedData = this.getRangedData(this.copyableRanges);
@@ -604,7 +605,6 @@ export class CopyPaste extends BasePlugin {
604
605
  this.hot.emptySelectedCells('CopyPaste.cut');
605
606
  this.hot.runHooks('afterCut', rangedData, this.copyableRanges);
606
607
  }
607
- event.preventDefault();
608
608
  }
609
609
 
610
610
  /**
@@ -614,10 +614,10 @@ export class CopyPaste extends BasePlugin {
614
614
  * @private
615
615
  */
616
616
  onPaste(event) {
617
- if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected()) {
618
- return;
619
- }
620
- if (!this.hot.getSettings().outsideClickDeselects && event.target !== this.hot.rootDocument.body) {
617
+ var _event$target3;
618
+ const focusedElement = this.hot.getFocusManager().getRefocusElement();
619
+ const isHotInput = (_event$target3 = event.target) === null || _event$target3 === void 0 ? void 0 : _event$target3.hasAttribute('data-hot-input');
620
+ if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || event.target instanceof HTMLElement && (isHotInput && event.target !== focusedElement || !isHotInput && event.target !== this.hot.rootDocument.body)) {
621
621
  return;
622
622
  }
623
623
  event.preventDefault();
@@ -260,13 +260,16 @@ class DropdownMenu extends _base.BasePlugin {
260
260
  from
261
261
  } = this.hot.getSelectedRangeLast();
262
262
  const offset = (0, _utils.getDocumentOffsetByElement)(this.menu.container, this.hot.rootDocument);
263
- const target = this.hot.getCell(-1, from.col, true);
263
+ const target = this.hot.getCell(-1, from.col, true).querySelector(`.${BUTTON_CLASS_NAME}`);
264
264
  const rect = target.getBoundingClientRect();
265
265
  this.open({
266
266
  left: rect.left + offset.left,
267
267
  top: rect.top + target.offsetHeight + offset.top
268
268
  }, {
269
- left: rect.width
269
+ left: rect.width,
270
+ right: 0,
271
+ above: 0,
272
+ below: 3
270
273
  });
271
274
  // Make sure the first item is selected (role=menuitem). Otherwise, screen readers
272
275
  // will block the Esc key for the whole menu.
@@ -433,9 +436,12 @@ function _onTableClick(event) {
433
436
  _classPrivateFieldSet(_isButtonClicked, this, false);
434
437
  this.open({
435
438
  left: rect.left + offset.left,
436
- top: rect.top + event.target.offsetHeight + 3 + offset.top
439
+ top: rect.top + event.target.offsetHeight + offset.top
437
440
  }, {
438
- left: rect.width
441
+ left: rect.width,
442
+ right: 0,
443
+ above: 0,
444
+ below: 3
439
445
  });
440
446
  }
441
447
  }