handsontable 0.0.0-next-1af4e47-20241125 → 0.0.0-next-fcb9b77-20241126

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

package/helpers/mixed.js CHANGED
@@ -134,7 +134,7 @@ const domMessages = {
134
134
  function _injectProductInfo(key, element) {
135
135
  const hasValidType = !isEmpty(key);
136
136
  const isNonCommercial = typeof key === 'string' && key.toLowerCase() === 'non-commercial-and-evaluation';
137
- const hotVersion = "0.0.0-next-1af4e47-20241125";
137
+ const hotVersion = "0.0.0-next-fcb9b77-20241126";
138
138
  let keyValidityDate;
139
139
  let consoleMessageState = 'invalid';
140
140
  let domMessageState = 'invalid';
package/helpers/mixed.mjs CHANGED
@@ -124,7 +124,7 @@ const domMessages = {
124
124
  export function _injectProductInfo(key, element) {
125
125
  const hasValidType = !isEmpty(key);
126
126
  const isNonCommercial = typeof key === 'string' && key.toLowerCase() === 'non-commercial-and-evaluation';
127
- const hotVersion = "0.0.0-next-1af4e47-20241125";
127
+ const hotVersion = "0.0.0-next-fcb9b77-20241126";
128
128
  let keyValidityDate;
129
129
  let consoleMessageState = 'invalid';
130
130
  let domMessageState = 'invalid';
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "url": "https://github.com/handsontable/handsontable/issues"
11
11
  },
12
12
  "author": "Handsoncode <hello@handsontable.com>",
13
- "version": "0.0.0-next-1af4e47-20241125",
13
+ "version": "0.0.0-next-fcb9b77-20241126",
14
14
  "main": "index",
15
15
  "module": "index.mjs",
16
16
  "jsnext:main": "index.mjs",
@@ -34,19 +34,8 @@ 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
- },
44
37
  name() {
45
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
46
- if ((0, _utils.hasSelectionAClass)(this, 'htLeft')) {
47
- label = (0, _utils.markLabelAsSelected)(label);
48
- }
49
- return label;
38
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
50
39
  },
51
40
  callback() {
52
41
  const selectedRange = this.getSelectedRange();
@@ -60,19 +49,8 @@ function alignmentItem() {
60
49
  disabled: false
61
50
  }, {
62
51
  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
- },
70
52
  name() {
71
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
72
- if ((0, _utils.hasSelectionAClass)(this, 'htCenter')) {
73
- label = (0, _utils.markLabelAsSelected)(label);
74
- }
75
- return label;
53
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
76
54
  },
77
55
  callback() {
78
56
  const selectedRange = this.getSelectedRange();
@@ -86,19 +64,8 @@ function alignmentItem() {
86
64
  disabled: false
87
65
  }, {
88
66
  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
- },
96
67
  name() {
97
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
98
- if ((0, _utils.hasSelectionAClass)(this, 'htRight')) {
99
- label = (0, _utils.markLabelAsSelected)(label);
100
- }
101
- return label;
68
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
102
69
  },
103
70
  callback() {
104
71
  const selectedRange = this.getSelectedRange();
@@ -112,19 +79,8 @@ function alignmentItem() {
112
79
  disabled: false
113
80
  }, {
114
81
  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
- },
122
82
  name() {
123
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
124
- if ((0, _utils.hasSelectionAClass)(this, 'htJustify')) {
125
- label = (0, _utils.markLabelAsSelected)(label);
126
- }
127
- return label;
83
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
128
84
  },
129
85
  callback() {
130
86
  const selectedRange = this.getSelectedRange();
@@ -140,19 +96,8 @@ function alignmentItem() {
140
96
  name: _separator.KEY
141
97
  }, {
142
98
  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
- },
150
99
  name() {
151
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
152
- if ((0, _utils.hasSelectionAClass)(this, 'htTop')) {
153
- label = (0, _utils.markLabelAsSelected)(label);
154
- }
155
- return label;
100
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
156
101
  },
157
102
  callback() {
158
103
  const selectedRange = this.getSelectedRange();
@@ -166,19 +111,8 @@ function alignmentItem() {
166
111
  disabled: false
167
112
  }, {
168
113
  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
- },
176
114
  name() {
177
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
178
- if ((0, _utils.hasSelectionAClass)(this, 'htMiddle')) {
179
- label = (0, _utils.markLabelAsSelected)(label);
180
- }
181
- return label;
115
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
182
116
  },
183
117
  callback() {
184
118
  const selectedRange = this.getSelectedRange();
@@ -192,19 +126,8 @@ function alignmentItem() {
192
126
  disabled: false
193
127
  }, {
194
128
  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
- },
202
129
  name() {
203
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
204
- if ((0, _utils.hasSelectionAClass)(this, 'htBottom')) {
205
- label = (0, _utils.markLabelAsSelected)(label);
206
- }
207
- return label;
130
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
208
131
  },
209
132
  callback() {
210
133
  const selectedRange = this.getSelectedRange();
@@ -1,4 +1,4 @@
1
- import { align, getAlignmentClasses, markLabelAsSelected, hasSelectionAClass } from "../utils.mjs";
1
+ import { align, getAlignmentClasses } 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,19 +28,8 @@ 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
- },
38
31
  name() {
39
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
40
- if (hasSelectionAClass(this, 'htLeft')) {
41
- label = markLabelAsSelected(label);
42
- }
43
- return label;
32
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_LEFT);
44
33
  },
45
34
  callback() {
46
35
  const selectedRange = this.getSelectedRange();
@@ -54,19 +43,8 @@ export default function alignmentItem() {
54
43
  disabled: false
55
44
  }, {
56
45
  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
- },
64
46
  name() {
65
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
66
- if (hasSelectionAClass(this, 'htCenter')) {
67
- label = markLabelAsSelected(label);
68
- }
69
- return label;
47
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_CENTER);
70
48
  },
71
49
  callback() {
72
50
  const selectedRange = this.getSelectedRange();
@@ -80,19 +58,8 @@ export default function alignmentItem() {
80
58
  disabled: false
81
59
  }, {
82
60
  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
- },
90
61
  name() {
91
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
92
- if (hasSelectionAClass(this, 'htRight')) {
93
- label = markLabelAsSelected(label);
94
- }
95
- return label;
62
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_RIGHT);
96
63
  },
97
64
  callback() {
98
65
  const selectedRange = this.getSelectedRange();
@@ -106,19 +73,8 @@ export default function alignmentItem() {
106
73
  disabled: false
107
74
  }, {
108
75
  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
- },
116
76
  name() {
117
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
118
- if (hasSelectionAClass(this, 'htJustify')) {
119
- label = markLabelAsSelected(label);
120
- }
121
- return label;
77
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_JUSTIFY);
122
78
  },
123
79
  callback() {
124
80
  const selectedRange = this.getSelectedRange();
@@ -134,19 +90,8 @@ export default function alignmentItem() {
134
90
  name: SEPARATOR
135
91
  }, {
136
92
  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
- },
144
93
  name() {
145
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
146
- if (hasSelectionAClass(this, 'htTop')) {
147
- label = markLabelAsSelected(label);
148
- }
149
- return label;
94
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_TOP);
150
95
  },
151
96
  callback() {
152
97
  const selectedRange = this.getSelectedRange();
@@ -160,19 +105,8 @@ export default function alignmentItem() {
160
105
  disabled: false
161
106
  }, {
162
107
  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
- },
170
108
  name() {
171
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
172
- if (hasSelectionAClass(this, 'htMiddle')) {
173
- label = markLabelAsSelected(label);
174
- }
175
- return label;
109
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_MIDDLE);
176
110
  },
177
111
  callback() {
178
112
  const selectedRange = this.getSelectedRange();
@@ -186,19 +120,8 @@ export default function alignmentItem() {
186
120
  disabled: false
187
121
  }, {
188
122
  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
- },
196
123
  name() {
197
- let label = this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
198
- if (hasSelectionAClass(this, 'htBottom')) {
199
- label = markLabelAsSelected(label);
200
- }
201
- return label;
124
+ return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_ALIGNMENT_BOTTOM);
202
125
  },
203
126
  callback() {
204
127
  const selectedRange = this.getSelectedRange();
@@ -6,7 +6,6 @@ exports.checkSelectionConsistency = checkSelectionConsistency;
6
6
  exports.getAlignmentClasses = getAlignmentClasses;
7
7
  exports.getAlignmentComparatorByClass = getAlignmentComparatorByClass;
8
8
  exports.getDocumentOffsetByElement = getDocumentOffsetByElement;
9
- exports.hasSelectionAClass = hasSelectionAClass;
10
9
  exports.markLabelAsSelected = markLabelAsSelected;
11
10
  exports.prepareHorizontalAlignClass = prepareHorizontalAlignClass;
12
11
  exports.prepareVerticalAlignClass = prepareVerticalAlignClass;
@@ -168,13 +167,4 @@ function getAlignmentComparatorByClass(htClassName) {
168
167
  const className = this.getCellMeta(row, col).className;
169
168
  return className && className.indexOf(htClassName) !== -1;
170
169
  };
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));
180
170
  }
@@ -156,13 +156,4 @@ export function getAlignmentComparatorByClass(htClassName) {
156
156
  const className = this.getCellMeta(row, col).className;
157
157
  return className && className.indexOf(htClassName) !== -1;
158
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));
168
159
  }
@@ -77,6 +77,7 @@ var _stateManager = /*#__PURE__*/new WeakMap();
77
77
  var _hidingIndexMapObserver = /*#__PURE__*/new WeakMap();
78
78
  var _focusInitialCoords = /*#__PURE__*/new WeakMap();
79
79
  var _isColumnsSelectionInProgress = /*#__PURE__*/new WeakMap();
80
+ var _recentlyHighlightCoords = /*#__PURE__*/new WeakMap();
80
81
  var _NestedHeaders_brand = /*#__PURE__*/new WeakSet();
81
82
  class NestedHeaders extends _base.BasePlugin {
82
83
  constructor() {
@@ -111,6 +112,14 @@ class NestedHeaders extends _base.BasePlugin {
111
112
  * @type {boolean}
112
113
  */
113
114
  _classPrivateFieldInitSpec(this, _isColumnsSelectionInProgress, false);
115
+ /**
116
+ * Keeps the last highlight position made by column selection. The coords are necessary to scroll
117
+ * the viewport to the correct position when the nested header is clicked when the `navigableHeaders`
118
+ * option is disabled.
119
+ *
120
+ * @type {CellCoords | null}
121
+ */
122
+ _classPrivateFieldInitSpec(this, _recentlyHighlightCoords, null);
114
123
  /**
115
124
  * Custom helper for getting widths of the nested headers.
116
125
  *
@@ -531,9 +540,13 @@ function _updateFocusHighlightPosition() {
531
540
  * indexes are used.
532
541
  *
533
542
  * @param {number} visualColumn A visual column index to which the viewport will be scrolled.
543
+ * @param {{ value: 'auto' | 'start' | 'end' }} snapping If `'start'`, viewport is scrolled to show
544
+ * the cell on the left of the table. If `'end'`, viewport is scrolled to show the cell on the right of
545
+ * the table. When `'auto'`, the viewport is scrolled only when the column is outside of the viewport.
534
546
  * @returns {number}
535
547
  */
536
- function _onBeforeViewportScrollHorizontally(visualColumn) {
548
+ function _onBeforeViewportScrollHorizontally(visualColumn, snapping) {
549
+ var _classPrivateFieldGet4;
537
550
  const selection = this.hot.getSelectedRangeLast();
538
551
  if (!selection) {
539
552
  return visualColumn;
@@ -541,20 +554,50 @@ function _onBeforeViewportScrollHorizontally(visualColumn) {
541
554
  const {
542
555
  highlight
543
556
  } = selection;
544
- const isNestedHeadersRange = highlight.isHeader() && highlight.col >= 0;
557
+ const {
558
+ navigableHeaders
559
+ } = this.hot.getSettings();
560
+ const isSelectedByColumnHeader = this.hot.selection.isSelectedByColumnHeader();
561
+ const highlightRow = navigableHeaders ? highlight.row : (_classPrivateFieldGet4 = _classPrivateFieldGet(_recentlyHighlightCoords, this)) === null || _classPrivateFieldGet4 === void 0 ? void 0 : _classPrivateFieldGet4.row;
562
+ const highlightColumn = isSelectedByColumnHeader ? visualColumn : highlight.col;
563
+ const isNestedHeadersRange = highlightRow < 0 && highlightColumn >= 0;
564
+ _classPrivateFieldSet(_recentlyHighlightCoords, this, null);
545
565
  if (!isNestedHeadersRange) {
546
566
  return visualColumn;
547
567
  }
548
- const firstColumn = this.hot.view.getFirstFullyVisibleColumn();
549
- const lastColumn = this.hot.view.getLastFullyVisibleColumn();
550
- const mostLeftColumnIndex = _classPrivateFieldGet(_stateManager, this).findLeftMostColumnIndex(highlight.row, highlight.col);
551
- const mostRightColumnIndex = _classPrivateFieldGet(_stateManager, this).findRightMostColumnIndex(highlight.row, highlight.col);
568
+ const firstVisibleColumn = this.hot.getFirstFullyVisibleColumn();
569
+ const lastVisibleColumn = this.hot.getLastFullyVisibleColumn();
570
+ const viewportWidth = lastVisibleColumn - firstVisibleColumn + 1;
571
+ const mostLeftColumnIndex = _classPrivateFieldGet(_stateManager, this).findLeftMostColumnIndex(highlightRow, highlightColumn);
572
+ const mostRightColumnIndex = _classPrivateFieldGet(_stateManager, this).findRightMostColumnIndex(highlightRow, highlightColumn);
573
+ const headerWidth = mostRightColumnIndex - mostLeftColumnIndex + 1;
552
574
 
553
- // do not scroll the viewport when the header is wider than the viewport
554
- if (mostLeftColumnIndex < firstColumn && mostRightColumnIndex > lastColumn) {
555
- return visualColumn;
575
+ // scroll the viewport always to the left when the header is wider than the viewport
576
+ if (mostLeftColumnIndex < firstVisibleColumn && mostRightColumnIndex > lastVisibleColumn) {
577
+ return mostLeftColumnIndex;
578
+ }
579
+ if (isSelectedByColumnHeader) {
580
+ let scrollColumnIndex = null;
581
+ if (mostLeftColumnIndex >= firstVisibleColumn && mostRightColumnIndex > lastVisibleColumn) {
582
+ if (headerWidth > viewportWidth) {
583
+ snapping.value = 'start';
584
+ scrollColumnIndex = mostLeftColumnIndex;
585
+ } else {
586
+ snapping.value = 'end';
587
+ scrollColumnIndex = mostRightColumnIndex;
588
+ }
589
+ } else if (mostLeftColumnIndex < firstVisibleColumn && mostRightColumnIndex <= lastVisibleColumn) {
590
+ if (headerWidth > viewportWidth) {
591
+ snapping.value = 'end';
592
+ scrollColumnIndex = mostRightColumnIndex;
593
+ } else {
594
+ snapping.value = 'start';
595
+ scrollColumnIndex = mostLeftColumnIndex;
596
+ }
597
+ }
598
+ return scrollColumnIndex;
556
599
  }
557
- return mostLeftColumnIndex < firstColumn ? mostLeftColumnIndex : mostRightColumnIndex;
600
+ return mostLeftColumnIndex <= firstVisibleColumn ? mostLeftColumnIndex : mostRightColumnIndex;
558
601
  }
559
602
  /**
560
603
  * Allows to control which header DOM element will be used to highlight.
@@ -625,13 +668,13 @@ function _onBeforeCopy(data, copyableRanges, _ref2) {
625
668
  }
626
669
  for (let column = startCol; column <= endCol; column++) {
627
670
  for (let row = startRow; row <= endRow; row++) {
628
- var _classPrivateFieldGet4;
671
+ var _classPrivateFieldGet5;
629
672
  const zeroBasedColumnHeaderLevel = rowsCount + row;
630
673
  const zeroBasedColumnIndex = column - startCol;
631
674
  if (zeroBasedColumnIndex === 0) {
632
675
  continue; // eslint-disable-line no-continue
633
676
  }
634
- const isRoot = (_classPrivateFieldGet4 = _classPrivateFieldGet(_stateManager, this).getHeaderTreeNodeData(row, column)) === null || _classPrivateFieldGet4 === void 0 ? void 0 : _classPrivateFieldGet4.isRoot;
677
+ const isRoot = (_classPrivateFieldGet5 = _classPrivateFieldGet(_stateManager, this).getHeaderTreeNodeData(row, column)) === null || _classPrivateFieldGet5 === void 0 ? void 0 : _classPrivateFieldGet5.isRoot;
635
678
  if (isRoot === false) {
636
679
  data[zeroBasedColumnHeaderLevel][zeroBasedColumnIndex] = '';
637
680
  }
@@ -817,8 +860,9 @@ function _onModifyTransformStart(delta) {
817
860
  *
818
861
  * @param {CellCoords} from The coords object where the selection starts.
819
862
  * @param {CellCoords} to The coords object where the selection ends.
863
+ * @param {CellCoords} highlight The coords object where the focus is.
820
864
  */
821
- function _onBeforeSelectColumns(from, to) {
865
+ function _onBeforeSelectColumns(from, to, highlight) {
822
866
  const headerLevel = from.row;
823
867
  const startNodeData = this._getHeaderTreeNodeDataByCoords({
824
868
  row: headerLevel,
@@ -828,6 +872,7 @@ function _onBeforeSelectColumns(from, to) {
828
872
  row: headerLevel,
829
873
  col: to.col
830
874
  });
875
+ _classPrivateFieldSet(_recentlyHighlightCoords, this, highlight.clone());
831
876
  if (to.col < from.col) {
832
877
  // Column selection from right to left
833
878
  if (startNodeData) {
@@ -912,10 +957,10 @@ function _onModifyColWidth(width, column) {
912
957
  * @returns {string} Returns the column header value to update.
913
958
  */
914
959
  function _onModifyColumnHeaderValue(value, visualColumnIndex, headerLevel) {
915
- var _classPrivateFieldGet5;
960
+ var _classPrivateFieldGet6;
916
961
  const {
917
962
  label
918
- } = (_classPrivateFieldGet5 = _classPrivateFieldGet(_stateManager, this).getHeaderTreeNodeData(headerLevel, visualColumnIndex)) !== null && _classPrivateFieldGet5 !== void 0 ? _classPrivateFieldGet5 : {
963
+ } = (_classPrivateFieldGet6 = _classPrivateFieldGet(_stateManager, this).getHeaderTreeNodeData(headerLevel, visualColumnIndex)) !== null && _classPrivateFieldGet6 !== void 0 ? _classPrivateFieldGet6 : {
919
964
  label: ''
920
965
  };
921
966
  return label;
@@ -73,6 +73,7 @@ var _stateManager = /*#__PURE__*/new WeakMap();
73
73
  var _hidingIndexMapObserver = /*#__PURE__*/new WeakMap();
74
74
  var _focusInitialCoords = /*#__PURE__*/new WeakMap();
75
75
  var _isColumnsSelectionInProgress = /*#__PURE__*/new WeakMap();
76
+ var _recentlyHighlightCoords = /*#__PURE__*/new WeakMap();
76
77
  var _NestedHeaders_brand = /*#__PURE__*/new WeakSet();
77
78
  export class NestedHeaders extends BasePlugin {
78
79
  constructor() {
@@ -107,6 +108,14 @@ export class NestedHeaders extends BasePlugin {
107
108
  * @type {boolean}
108
109
  */
109
110
  _classPrivateFieldInitSpec(this, _isColumnsSelectionInProgress, false);
111
+ /**
112
+ * Keeps the last highlight position made by column selection. The coords are necessary to scroll
113
+ * the viewport to the correct position when the nested header is clicked when the `navigableHeaders`
114
+ * option is disabled.
115
+ *
116
+ * @type {CellCoords | null}
117
+ */
118
+ _classPrivateFieldInitSpec(this, _recentlyHighlightCoords, null);
110
119
  /**
111
120
  * Custom helper for getting widths of the nested headers.
112
121
  *
@@ -526,9 +535,13 @@ function _updateFocusHighlightPosition() {
526
535
  * indexes are used.
527
536
  *
528
537
  * @param {number} visualColumn A visual column index to which the viewport will be scrolled.
538
+ * @param {{ value: 'auto' | 'start' | 'end' }} snapping If `'start'`, viewport is scrolled to show
539
+ * the cell on the left of the table. If `'end'`, viewport is scrolled to show the cell on the right of
540
+ * the table. When `'auto'`, the viewport is scrolled only when the column is outside of the viewport.
529
541
  * @returns {number}
530
542
  */
531
- function _onBeforeViewportScrollHorizontally(visualColumn) {
543
+ function _onBeforeViewportScrollHorizontally(visualColumn, snapping) {
544
+ var _classPrivateFieldGet4;
532
545
  const selection = this.hot.getSelectedRangeLast();
533
546
  if (!selection) {
534
547
  return visualColumn;
@@ -536,20 +549,50 @@ function _onBeforeViewportScrollHorizontally(visualColumn) {
536
549
  const {
537
550
  highlight
538
551
  } = selection;
539
- const isNestedHeadersRange = highlight.isHeader() && highlight.col >= 0;
552
+ const {
553
+ navigableHeaders
554
+ } = this.hot.getSettings();
555
+ const isSelectedByColumnHeader = this.hot.selection.isSelectedByColumnHeader();
556
+ const highlightRow = navigableHeaders ? highlight.row : (_classPrivateFieldGet4 = _classPrivateFieldGet(_recentlyHighlightCoords, this)) === null || _classPrivateFieldGet4 === void 0 ? void 0 : _classPrivateFieldGet4.row;
557
+ const highlightColumn = isSelectedByColumnHeader ? visualColumn : highlight.col;
558
+ const isNestedHeadersRange = highlightRow < 0 && highlightColumn >= 0;
559
+ _classPrivateFieldSet(_recentlyHighlightCoords, this, null);
540
560
  if (!isNestedHeadersRange) {
541
561
  return visualColumn;
542
562
  }
543
- const firstColumn = this.hot.view.getFirstFullyVisibleColumn();
544
- const lastColumn = this.hot.view.getLastFullyVisibleColumn();
545
- const mostLeftColumnIndex = _classPrivateFieldGet(_stateManager, this).findLeftMostColumnIndex(highlight.row, highlight.col);
546
- const mostRightColumnIndex = _classPrivateFieldGet(_stateManager, this).findRightMostColumnIndex(highlight.row, highlight.col);
563
+ const firstVisibleColumn = this.hot.getFirstFullyVisibleColumn();
564
+ const lastVisibleColumn = this.hot.getLastFullyVisibleColumn();
565
+ const viewportWidth = lastVisibleColumn - firstVisibleColumn + 1;
566
+ const mostLeftColumnIndex = _classPrivateFieldGet(_stateManager, this).findLeftMostColumnIndex(highlightRow, highlightColumn);
567
+ const mostRightColumnIndex = _classPrivateFieldGet(_stateManager, this).findRightMostColumnIndex(highlightRow, highlightColumn);
568
+ const headerWidth = mostRightColumnIndex - mostLeftColumnIndex + 1;
547
569
 
548
- // do not scroll the viewport when the header is wider than the viewport
549
- if (mostLeftColumnIndex < firstColumn && mostRightColumnIndex > lastColumn) {
550
- return visualColumn;
570
+ // scroll the viewport always to the left when the header is wider than the viewport
571
+ if (mostLeftColumnIndex < firstVisibleColumn && mostRightColumnIndex > lastVisibleColumn) {
572
+ return mostLeftColumnIndex;
573
+ }
574
+ if (isSelectedByColumnHeader) {
575
+ let scrollColumnIndex = null;
576
+ if (mostLeftColumnIndex >= firstVisibleColumn && mostRightColumnIndex > lastVisibleColumn) {
577
+ if (headerWidth > viewportWidth) {
578
+ snapping.value = 'start';
579
+ scrollColumnIndex = mostLeftColumnIndex;
580
+ } else {
581
+ snapping.value = 'end';
582
+ scrollColumnIndex = mostRightColumnIndex;
583
+ }
584
+ } else if (mostLeftColumnIndex < firstVisibleColumn && mostRightColumnIndex <= lastVisibleColumn) {
585
+ if (headerWidth > viewportWidth) {
586
+ snapping.value = 'end';
587
+ scrollColumnIndex = mostRightColumnIndex;
588
+ } else {
589
+ snapping.value = 'start';
590
+ scrollColumnIndex = mostLeftColumnIndex;
591
+ }
592
+ }
593
+ return scrollColumnIndex;
551
594
  }
552
- return mostLeftColumnIndex < firstColumn ? mostLeftColumnIndex : mostRightColumnIndex;
595
+ return mostLeftColumnIndex <= firstVisibleColumn ? mostLeftColumnIndex : mostRightColumnIndex;
553
596
  }
554
597
  /**
555
598
  * Allows to control which header DOM element will be used to highlight.
@@ -620,13 +663,13 @@ function _onBeforeCopy(data, copyableRanges, _ref2) {
620
663
  }
621
664
  for (let column = startCol; column <= endCol; column++) {
622
665
  for (let row = startRow; row <= endRow; row++) {
623
- var _classPrivateFieldGet4;
666
+ var _classPrivateFieldGet5;
624
667
  const zeroBasedColumnHeaderLevel = rowsCount + row;
625
668
  const zeroBasedColumnIndex = column - startCol;
626
669
  if (zeroBasedColumnIndex === 0) {
627
670
  continue; // eslint-disable-line no-continue
628
671
  }
629
- const isRoot = (_classPrivateFieldGet4 = _classPrivateFieldGet(_stateManager, this).getHeaderTreeNodeData(row, column)) === null || _classPrivateFieldGet4 === void 0 ? void 0 : _classPrivateFieldGet4.isRoot;
672
+ const isRoot = (_classPrivateFieldGet5 = _classPrivateFieldGet(_stateManager, this).getHeaderTreeNodeData(row, column)) === null || _classPrivateFieldGet5 === void 0 ? void 0 : _classPrivateFieldGet5.isRoot;
630
673
  if (isRoot === false) {
631
674
  data[zeroBasedColumnHeaderLevel][zeroBasedColumnIndex] = '';
632
675
  }
@@ -812,8 +855,9 @@ function _onModifyTransformStart(delta) {
812
855
  *
813
856
  * @param {CellCoords} from The coords object where the selection starts.
814
857
  * @param {CellCoords} to The coords object where the selection ends.
858
+ * @param {CellCoords} highlight The coords object where the focus is.
815
859
  */
816
- function _onBeforeSelectColumns(from, to) {
860
+ function _onBeforeSelectColumns(from, to, highlight) {
817
861
  const headerLevel = from.row;
818
862
  const startNodeData = this._getHeaderTreeNodeDataByCoords({
819
863
  row: headerLevel,
@@ -823,6 +867,7 @@ function _onBeforeSelectColumns(from, to) {
823
867
  row: headerLevel,
824
868
  col: to.col
825
869
  });
870
+ _classPrivateFieldSet(_recentlyHighlightCoords, this, highlight.clone());
826
871
  if (to.col < from.col) {
827
872
  // Column selection from right to left
828
873
  if (startNodeData) {
@@ -907,10 +952,10 @@ function _onModifyColWidth(width, column) {
907
952
  * @returns {string} Returns the column header value to update.
908
953
  */
909
954
  function _onModifyColumnHeaderValue(value, visualColumnIndex, headerLevel) {
910
- var _classPrivateFieldGet5;
955
+ var _classPrivateFieldGet6;
911
956
  const {
912
957
  label
913
- } = (_classPrivateFieldGet5 = _classPrivateFieldGet(_stateManager, this).getHeaderTreeNodeData(headerLevel, visualColumnIndex)) !== null && _classPrivateFieldGet5 !== void 0 ? _classPrivateFieldGet5 : {
958
+ } = (_classPrivateFieldGet6 = _classPrivateFieldGet(_stateManager, this).getHeaderTreeNodeData(headerLevel, visualColumnIndex)) !== null && _classPrivateFieldGet6 !== void 0 ? _classPrivateFieldGet6 : {
914
959
  label: ''
915
960
  };
916
961
  return label;
@@ -1208,9 +1208,11 @@ class Selection {
1208
1208
  if (!this.isSelected()) {
1209
1209
  return;
1210
1210
  }
1211
- const focusHighlight = this.highlight.getFocus();
1212
1211
  const currentLayer = this.getLayerLevel();
1213
- focusHighlight.commit().syncWith(this.selectedRange.current());
1212
+ const cellRange = this.selectedRange.current();
1213
+ if (this.highlight.isEnabledFor(_highlight.FOCUS_TYPE, cellRange.highlight)) {
1214
+ this.highlight.getFocus().commit().syncWith(cellRange);
1215
+ }
1214
1216
 
1215
1217
  // Rewriting rendered ranges going through all layers.
1216
1218
  for (let layerLevel = 0; layerLevel < this.selectedRange.size(); layerLevel += 1) {