handsontable 0.0.0-next-2c41c5b-20250814 → 0.0.0-next-fce5825-20250822

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 (126) hide show
  1. package/base.js +2 -2
  2. package/base.mjs +2 -2
  3. package/cellTypes/autocompleteType/autocompleteType.js +1 -4
  4. package/cellTypes/autocompleteType/autocompleteType.mjs +1 -4
  5. package/cellTypes/checkboxType/checkboxType.js +1 -3
  6. package/cellTypes/checkboxType/checkboxType.mjs +1 -3
  7. package/cellTypes/dropdownType/dropdownType.js +1 -4
  8. package/cellTypes/dropdownType/dropdownType.mjs +1 -4
  9. package/cellTypes/numericType/numericType.js +1 -3
  10. package/cellTypes/numericType/numericType.mjs +1 -3
  11. package/core/focusCatcher/index.js +37 -20
  12. package/core/focusCatcher/index.mjs +37 -20
  13. package/core/focusCatcher/utils.js +3 -64
  14. package/core/focusCatcher/utils.mjs +1 -60
  15. package/core/hooks/constants.js +58 -0
  16. package/core/hooks/constants.mjs +58 -0
  17. package/core/hooks/index.d.ts +7 -0
  18. package/core.d.ts +0 -1
  19. package/core.js +59 -55
  20. package/core.mjs +61 -57
  21. package/dataMap/dataMap.js +3 -13
  22. package/dataMap/dataMap.mjs +4 -14
  23. package/dataMap/dataSource.js +0 -16
  24. package/dataMap/dataSource.mjs +0 -16
  25. package/dataMap/metaManager/lazyFactoryMap.js +3 -4
  26. package/dataMap/metaManager/lazyFactoryMap.mjs +1 -2
  27. package/dataMap/metaManager/metaLayers/cellMeta.js +2 -3
  28. package/dataMap/metaManager/metaLayers/cellMeta.mjs +2 -3
  29. package/dataMap/metaManager/metaSchema.js +97 -68
  30. package/dataMap/metaManager/metaSchema.mjs +97 -68
  31. package/dataMap/metaManager/utils.js +11 -0
  32. package/dataMap/metaManager/utils.mjs +10 -0
  33. package/dist/handsontable.css +103 -5
  34. package/dist/handsontable.full.css +103 -5
  35. package/dist/handsontable.full.js +2770 -1954
  36. package/dist/handsontable.full.min.css +3 -3
  37. package/dist/handsontable.full.min.js +67 -67
  38. package/dist/handsontable.js +2772 -1956
  39. package/dist/handsontable.min.css +3 -3
  40. package/dist/handsontable.min.js +27 -27
  41. package/editors/autocompleteEditor/autocompleteEditor.js +8 -33
  42. package/editors/autocompleteEditor/autocompleteEditor.mjs +9 -34
  43. package/editors/baseEditor/baseEditor.js +2 -2
  44. package/editors/baseEditor/baseEditor.mjs +2 -2
  45. package/helpers/a11y.js +5 -1
  46. package/helpers/a11y.mjs +3 -1
  47. package/helpers/mixed.js +64 -1
  48. package/helpers/mixed.mjs +62 -1
  49. package/helpers/number.js +0 -28
  50. package/helpers/number.mjs +0 -26
  51. package/helpers/string.js +0 -19
  52. package/helpers/string.mjs +0 -18
  53. package/index.d.ts +9 -0
  54. package/package.json +6 -1
  55. package/plugins/autofill/autofill.js +3 -50
  56. package/plugins/autofill/autofill.mjs +3 -50
  57. package/plugins/base/base.js +75 -14
  58. package/plugins/base/base.mjs +75 -14
  59. package/plugins/contextMenu/contextMenu.js +1 -0
  60. package/plugins/contextMenu/contextMenu.mjs +1 -0
  61. package/plugins/copyPaste/copyPaste.js +28 -61
  62. package/plugins/copyPaste/copyPaste.mjs +29 -62
  63. package/plugins/dialog/dialog.d.ts +23 -0
  64. package/plugins/dialog/dialog.js +469 -0
  65. package/plugins/dialog/dialog.mjs +465 -0
  66. package/plugins/dialog/index.d.ts +1 -0
  67. package/plugins/dialog/index.js +7 -0
  68. package/plugins/dialog/index.mjs +1 -0
  69. package/plugins/dialog/ui.js +240 -0
  70. package/plugins/dialog/ui.mjs +235 -0
  71. package/plugins/dropdownMenu/dropdownMenu.js +1 -0
  72. package/plugins/dropdownMenu/dropdownMenu.mjs +1 -0
  73. package/plugins/index.d.ts +3 -0
  74. package/plugins/index.js +3 -0
  75. package/plugins/index.mjs +3 -1
  76. package/plugins/pagination/focusController.js +27 -0
  77. package/plugins/pagination/focusController.mjs +23 -0
  78. package/plugins/pagination/pagination.js +165 -18
  79. package/plugins/pagination/pagination.mjs +165 -18
  80. package/plugins/pagination/ui.js +101 -62
  81. package/plugins/pagination/ui.mjs +102 -63
  82. package/selection/range.js +11 -0
  83. package/selection/range.mjs +11 -0
  84. package/selection/selection.js +63 -2
  85. package/selection/selection.mjs +63 -2
  86. package/selection/utils.js +2 -1
  87. package/selection/utils.mjs +2 -1
  88. package/settings.d.ts +3 -3
  89. package/shortcuts/context.js +4 -1
  90. package/shortcuts/context.mjs +4 -1
  91. package/shortcuts/manager.js +17 -3
  92. package/shortcuts/manager.mjs +17 -3
  93. package/styles/handsontable.css +106 -22
  94. package/styles/handsontable.min.css +3 -3
  95. package/styles/ht-theme-horizon.css +24 -6
  96. package/styles/ht-theme-horizon.min.css +3 -3
  97. package/styles/ht-theme-main.css +52 -34
  98. package/styles/ht-theme-main.min.css +3 -3
  99. package/tableView.js +7 -2
  100. package/tableView.mjs +7 -2
  101. package/{core/focusCatcher → utils}/focusDetector.js +29 -11
  102. package/{core/focusCatcher → utils}/focusDetector.mjs +29 -11
  103. package/validators/autocompleteValidator/autocompleteValidator.js +1 -2
  104. package/validators/autocompleteValidator/autocompleteValidator.mjs +1 -2
  105. package/cellTypes/autocompleteType/accessors/index.js +0 -7
  106. package/cellTypes/autocompleteType/accessors/index.mjs +0 -2
  107. package/cellTypes/autocompleteType/accessors/valueGetter.js +0 -14
  108. package/cellTypes/autocompleteType/accessors/valueGetter.mjs +0 -10
  109. package/cellTypes/autocompleteType/accessors/valueSetter.js +0 -25
  110. package/cellTypes/autocompleteType/accessors/valueSetter.mjs +0 -21
  111. package/cellTypes/checkboxType/accessors/index.js +0 -5
  112. package/cellTypes/checkboxType/accessors/index.mjs +0 -1
  113. package/cellTypes/checkboxType/accessors/valueSetter.js +0 -26
  114. package/cellTypes/checkboxType/accessors/valueSetter.mjs +0 -22
  115. package/cellTypes/dropdownType/accessors/index.js +0 -7
  116. package/cellTypes/dropdownType/accessors/index.mjs +0 -2
  117. package/cellTypes/dropdownType/accessors/valueGetter.js +0 -14
  118. package/cellTypes/dropdownType/accessors/valueGetter.mjs +0 -10
  119. package/cellTypes/dropdownType/accessors/valueSetter.js +0 -17
  120. package/cellTypes/dropdownType/accessors/valueSetter.mjs +0 -13
  121. package/cellTypes/numericType/accessors/index.js +0 -5
  122. package/cellTypes/numericType/accessors/index.mjs +0 -1
  123. package/cellTypes/numericType/accessors/valueSetter.js +0 -19
  124. package/cellTypes/numericType/accessors/valueSetter.mjs +0 -15
  125. package/utils/valueAccessors.js +0 -45
  126. package/utils/valueAccessors.mjs +0 -40
@@ -14,6 +14,8 @@ var _a11yAnnouncer = require("../../utils/a11yAnnouncer");
14
14
  var _strategies = require("./strategies");
15
15
  var _templateLiteralTag = require("../../helpers/templateLiteralTag");
16
16
  var _console = require("../../helpers/console");
17
+ var _focusController2 = require("./focusController");
18
+ var _focusDetector2 = require("../../utils/focusDetector");
17
19
  function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
18
20
  function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
19
21
  function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
@@ -22,6 +24,8 @@ function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a),
22
24
  function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
23
25
  const PLUGIN_KEY = exports.PLUGIN_KEY = 'pagination';
24
26
  const PLUGIN_PRIORITY = exports.PLUGIN_PRIORITY = 900;
27
+ const SHORTCUTS_GROUP = PLUGIN_KEY;
28
+ const SHORTCUTS_CONTEXT_NAME = `plugin:${PLUGIN_KEY}`;
25
29
  const AUTO_PAGE_SIZE_WARNING = (0, _templateLiteralTag.toSingleLine)`The \`auto\` page size setting requires the \`autoRowSize\`\x20
26
30
  plugin to be enabled. Set the \`autoRowSize: true\` in the configuration to ensure correct behavior.`;
27
31
 
@@ -106,13 +110,15 @@ var _ui = /*#__PURE__*/new WeakMap();
106
110
  var _calcStrategy = /*#__PURE__*/new WeakMap();
107
111
  var _internalExecutionCall = /*#__PURE__*/new WeakMap();
108
112
  var _internalRenderCall = /*#__PURE__*/new WeakMap();
113
+ var _focusController = /*#__PURE__*/new WeakMap();
114
+ var _focusDetector = /*#__PURE__*/new WeakMap();
109
115
  var _Pagination_brand = /*#__PURE__*/new WeakSet();
110
116
  var _onIndexCacheUpdate = /*#__PURE__*/new WeakMap();
111
117
  class Pagination extends _base.BasePlugin {
112
118
  constructor() {
113
119
  super(...arguments);
114
120
  /**
115
- * Updates the visibility state of the pagination sections based on the current settings.
121
+ * Bind the events used by the plugin.
116
122
  */
117
123
  _classPrivateMethodInitSpec(this, _Pagination_brand);
118
124
  /**
@@ -162,6 +168,18 @@ class Pagination extends _base.BasePlugin {
162
168
  * @type {boolean}
163
169
  */
164
170
  _classPrivateFieldInitSpec(this, _internalRenderCall, false);
171
+ /**
172
+ * Pagination focus controller instance.
173
+ *
174
+ * @type {PaginationController}
175
+ */
176
+ _classPrivateFieldInitSpec(this, _focusController, null);
177
+ /**
178
+ * Pagination focus detector instance.
179
+ *
180
+ * @type {object}
181
+ */
182
+ _classPrivateFieldInitSpec(this, _focusDetector, null);
165
183
  /**
166
184
  * IndexMapper cache update listener. Once the cache is updated, we need to recompute
167
185
  * the pagination state.
@@ -230,7 +248,7 @@ class Pagination extends _base.BasePlugin {
230
248
  _classPrivateFieldSet(_calcStrategy, this, (0, _strategies.createPaginatorStrategy)(_classPrivateFieldGet(_pageSize, this) === 'auto' ? 'auto' : 'fixed'));
231
249
  if (!_classPrivateFieldGet(_ui, this)) {
232
250
  _classPrivateFieldSet(_ui, this, new _ui2.PaginationUI({
233
- rootElement: this.hot.rootElement,
251
+ rootElement: this.hot.rootGridElement,
234
252
  uiContainer: this.getSetting('uiContainer'),
235
253
  isRtl: this.hot.isRtl(),
236
254
  themeName: this.hot.getSettings().themeName,
@@ -241,8 +259,35 @@ class Pagination extends _base.BasePlugin {
241
259
  a11yAnnouncer: message => (0, _a11yAnnouncer.announce)(message)
242
260
  }));
243
261
  _assertClassBrand(_Pagination_brand, this, _updateSectionsVisibilityState).call(this);
244
- _classPrivateFieldGet(_ui, this).addLocalHook('firstPageClick', () => this.firstPage()).addLocalHook('prevPageClick', () => this.prevPage()).addLocalHook('nextPageClick', () => this.nextPage()).addLocalHook('lastPageClick', () => this.lastPage()).addLocalHook('pageSizeChange', pageSize => this.setPageSize(pageSize));
262
+ _classPrivateFieldGet(_ui, this).addLocalHook('firstPageClick', () => this.firstPage()).addLocalHook('prevPageClick', () => this.prevPage()).addLocalHook('nextPageClick', () => this.nextPage()).addLocalHook('lastPageClick', () => this.lastPage()).addLocalHook('pageSizeChange', pageSize => this.setPageSize(pageSize)).addLocalHook('focus', element => {
263
+ _classPrivateFieldGet(_focusController, this).setCurrentPage(_classPrivateFieldGet(_ui, this).getFocusableElements().indexOf(element));
264
+ this.hot.unlisten();
265
+ this.hot.getShortcutManager().setActiveContextName(SHORTCUTS_CONTEXT_NAME);
266
+ this.hot.listen();
267
+ _classPrivateFieldGet(_focusDetector, this).deactivate();
268
+ });
269
+ }
270
+ if (!_classPrivateFieldGet(_focusController, this)) {
271
+ _classPrivateFieldSet(_focusController, this, (0, _focusController2.createPaginationFocusController)({
272
+ focusableElements: () => _classPrivateFieldGet(_ui, this).getFocusableElements()
273
+ }));
245
274
  }
275
+ if (!_classPrivateFieldGet(_focusDetector, this)) {
276
+ _classPrivateFieldSet(_focusDetector, this, (0, _focusDetector2.installFocusDetector)(this.hot, _classPrivateFieldGet(_ui, this).getContainer(), {
277
+ onFocus: from => {
278
+ this.hot.getShortcutManager().setActiveContextName(SHORTCUTS_CONTEXT_NAME);
279
+ this.hot.listen();
280
+ if (from === 'from_above') {
281
+ _classPrivateFieldGet(_focusController, this).toFirstItem();
282
+ } else {
283
+ _classPrivateFieldGet(_focusController, this).toLastItem();
284
+ }
285
+ _classPrivateFieldGet(_focusDetector, this).deactivate();
286
+ }
287
+ }));
288
+ }
289
+ _assertClassBrand(_Pagination_brand, this, _registerEvents).call(this);
290
+ _assertClassBrand(_Pagination_brand, this, _registerShortcuts).call(this);
246
291
 
247
292
  // Place the onInit hook before others to make sure that the pagination state is computed
248
293
  // and applied to the index mapper before AutoColumnSize plugin begins calculate the column sizes.
@@ -324,6 +369,18 @@ class Pagination extends _base.BasePlugin {
324
369
  }
325
370
  return _assertClassBrand(_Pagination_brand, _this, _onAfterSetTheme).call(_this, ...args);
326
371
  });
372
+ this.addHook('afterDialogShow', function () {
373
+ for (var _len12 = arguments.length, args = new Array(_len12), _key12 = 0; _key12 < _len12; _key12++) {
374
+ args[_key12] = arguments[_key12];
375
+ }
376
+ return _assertClassBrand(_Pagination_brand, _this, _onAfterDialogShow).call(_this, ...args);
377
+ });
378
+ this.addHook('beforeDialogHide', function () {
379
+ for (var _len13 = arguments.length, args = new Array(_len13), _key13 = 0; _key13 < _len13; _key13++) {
380
+ args[_key13] = arguments[_key13];
381
+ }
382
+ return _assertClassBrand(_Pagination_brand, _this, _onAfterDialogHide).call(_this, ...args);
383
+ });
327
384
  this.hot.rowIndexMapper.addLocalHook('cacheUpdated', _classPrivateFieldGet(_onIndexCacheUpdate, this));
328
385
  super.enablePlugin();
329
386
  }
@@ -345,9 +402,9 @@ class Pagination extends _base.BasePlugin {
345
402
  this.hot.rowIndexMapper.removeLocalHook('cacheUpdated', _classPrivateFieldGet(_onIndexCacheUpdate, this)).unregisterMap(this.pluginName);
346
403
  _classPrivateFieldGet(_ui, this).destroy();
347
404
  _classPrivateFieldSet(_ui, this, null);
405
+ _assertClassBrand(_Pagination_brand, this, _unregisterShortcuts).call(this);
348
406
  super.disablePlugin();
349
407
  }
350
-
351
408
  /**
352
409
  * Gets the pagination current state. Returns an object with the following properties:
353
410
  * - `currentPage`: The current page number.
@@ -603,6 +660,11 @@ class Pagination extends _base.BasePlugin {
603
660
  _classPrivateFieldGet(_ui, this).setNavigationSectionVisibility(false);
604
661
  this.hot.runHooks('afterPageNavigationVisibilityChange', false);
605
662
  }
663
+
664
+ /**
665
+ * Updates the visibility state of the pagination sections based on the current settings.
666
+ */
667
+
606
668
  /**
607
669
  * Destroys the plugin instance.
608
670
  */
@@ -616,6 +678,59 @@ class Pagination extends _base.BasePlugin {
616
678
  }
617
679
  }
618
680
  exports.Pagination = Pagination;
681
+ function _registerEvents() {
682
+ // TODO: move to general focus manager module
683
+ this.eventManager.addEventListener(this.hot.rootDocument, 'mouseup', event => {
684
+ const container = _classPrivateFieldGet(_ui, this).getContainer();
685
+ if (!container.contains(event.target) && this.hot.getShortcutManager().getActiveContextName() === SHORTCUTS_CONTEXT_NAME) {
686
+ _classPrivateFieldGet(_focusDetector, this).activate();
687
+ _classPrivateFieldGet(_focusController, this).clear();
688
+ this.hot.getShortcutManager().setActiveContextName('grid');
689
+ }
690
+ });
691
+ }
692
+ /**
693
+ * Register shortcuts responsible for navigating through the pagination.
694
+ */
695
+ function _registerShortcuts() {
696
+ var _manager$getContext;
697
+ const manager = this.hot.getShortcutManager();
698
+ const pluginContext = (_manager$getContext = manager.getContext(SHORTCUTS_CONTEXT_NAME)) !== null && _manager$getContext !== void 0 ? _manager$getContext : manager.addContext(SHORTCUTS_CONTEXT_NAME, 'global');
699
+ pluginContext.addShortcut({
700
+ keys: [['Shift', 'Tab'], ['Tab']],
701
+ preventDefault: false,
702
+ callback: event => {
703
+ let previousIndex = _classPrivateFieldGet(_focusController, this).getCurrentPage();
704
+ if (event.shiftKey) {
705
+ _classPrivateFieldGet(_focusController, this).toPreviousItem();
706
+ const currentPage = _classPrivateFieldGet(_focusController, this).getCurrentPage();
707
+ if (currentPage >= previousIndex) {
708
+ _assertClassBrand(_Pagination_brand, this, _unFocusPagination).call(this);
709
+ return;
710
+ }
711
+ previousIndex = currentPage;
712
+ } else {
713
+ _classPrivateFieldGet(_focusController, this).toNextItem();
714
+ const currentPage = _classPrivateFieldGet(_focusController, this).getCurrentPage();
715
+ if (currentPage <= previousIndex) {
716
+ _assertClassBrand(_Pagination_brand, this, _unFocusPagination).call(this);
717
+ return;
718
+ }
719
+ previousIndex = currentPage;
720
+ }
721
+ event.preventDefault();
722
+ },
723
+ group: SHORTCUTS_GROUP
724
+ });
725
+ }
726
+ /**
727
+ * Unregister shortcuts responsible for navigating through the pagination.
728
+ */
729
+ function _unregisterShortcuts() {
730
+ const shortcutManager = this.hot.getShortcutManager();
731
+ const pluginContext = shortcutManager.getContext(SHORTCUTS_CONTEXT_NAME);
732
+ pluginContext.removeShortcutsByGroup(SHORTCUTS_GROUP);
733
+ }
619
734
  function _updateSectionsVisibilityState() {
620
735
  if (this.getSetting('showPageSize')) {
621
736
  this.showPageSizeSection();
@@ -688,10 +803,16 @@ function _computeAndApplyState() {
688
803
  this.hot.rowIndexMapper.updateCache(true);
689
804
  }
690
805
  _classPrivateFieldSet(_internalExecutionCall, this, false);
806
+ const paginationData = this.getPaginationData();
691
807
  _classPrivateFieldGet(_ui, this).updateState({
692
- ...this.getPaginationData(),
808
+ ...paginationData,
693
809
  totalRenderedRows: renderableRowsLength
694
810
  });
811
+ if ((this.getSetting('showPageSize') || this.getSetting('showNavigation')) && paginationData.totalPages > 1) {
812
+ _classPrivateFieldGet(_focusDetector, this).activate();
813
+ } else {
814
+ _classPrivateFieldGet(_focusDetector, this).deactivate();
815
+ }
695
816
  }
696
817
  /**
697
818
  * Based on the external factors (like the scroll position of the table, size etc.) it computes
@@ -842,6 +963,24 @@ function _onAfterRender() {
842
963
  const width = view.isHorizontallyScrollableByWindow() ? view.getTotalTableWidth() : view.getWorkspaceWidth();
843
964
  _classPrivateFieldGet(_ui, this).updateWidth(width).refreshBorderState();
844
965
  }
966
+ /**
967
+ * Called before the height of the table is changed. It adjusts the table height to fit the pagination container
968
+ * in declared height.
969
+ *
970
+ * @param {number|string} height Table height.
971
+ * @returns {string} Returns the new table height.
972
+ */
973
+ function _onBeforeHeightChange(height) {
974
+ if (this.getSetting('uiContainer')) {
975
+ return height;
976
+ }
977
+ const isPixelValue = typeof height === 'number' || typeof height === 'string' && /^\d+$/.test(height) || typeof height === 'string' && height.endsWith('px');
978
+ if (!isPixelValue) {
979
+ return height;
980
+ }
981
+ const heightValue = typeof height === 'string' && height.endsWith('px') ? height : `${height}px`;
982
+ return `calc(${heightValue} - ${_classPrivateFieldGet(_ui, this).getHeight()}px)`;
983
+ }
845
984
  /**
846
985
  * Called after the initialization of the plugin. It computes the initial state of the pagination.
847
986
  */
@@ -864,19 +1003,6 @@ function _onAfterScrollVertically() {
864
1003
  function _onAfterLanguageChange() {
865
1004
  _assertClassBrand(_Pagination_brand, this, _computeAndApplyState).call(this);
866
1005
  }
867
- /**
868
- * Called before the height of the table is changed. It adjusts the table height to fit the pagination container
869
- * in declared height.
870
- *
871
- * @param {number} height Table height.
872
- * @returns {string} Returns the new table height.
873
- */
874
- function _onBeforeHeightChange(height) {
875
- if (this.getSetting('uiContainer')) {
876
- return height;
877
- }
878
- return `calc(${height}${/[0-9]$/.test(height) ? 'px' : ''} - ${_classPrivateFieldGet(_ui, this).getHeight()}px)`;
879
- }
880
1006
  /**
881
1007
  * Called after the theme is set. It updates the theme of the pagination container.
882
1008
  *
@@ -884,4 +1010,25 @@ function _onBeforeHeightChange(height) {
884
1010
  */
885
1011
  function _onAfterSetTheme(themeName) {
886
1012
  _classPrivateFieldGet(_ui, this).updateTheme(themeName);
1013
+ }
1014
+ /**
1015
+ * Unfocuses the pagination and sets the active context for the shortcuts.
1016
+ */
1017
+ function _unFocusPagination() {
1018
+ _classPrivateFieldGet(_focusDetector, this).activate();
1019
+ _classPrivateFieldGet(_focusController, this).clear();
1020
+ this.hot.unlisten();
1021
+ this.hot.getShortcutManager().setActiveContextName('grid');
1022
+ }
1023
+ /**
1024
+ * Called after the dialog is shown. It sets the active context for the shortcuts.
1025
+ */
1026
+ function _onAfterDialogShow() {
1027
+ _classPrivateFieldGet(_focusDetector, this).deactivate();
1028
+ }
1029
+ /**
1030
+ * Called after the dialog is hidden. It sets the active context for the shortcuts.
1031
+ */
1032
+ function _onAfterDialogHide() {
1033
+ _classPrivateFieldGet(_focusDetector, this).activate();
887
1034
  }
@@ -17,8 +17,12 @@ import { announce } from "../../utils/a11yAnnouncer.mjs";
17
17
  import { createPaginatorStrategy } from "./strategies/index.mjs";
18
18
  import { toSingleLine } from "../../helpers/templateLiteralTag.mjs";
19
19
  import { warn } from "../../helpers/console.mjs";
20
+ import { createPaginationFocusController } from "./focusController.mjs";
21
+ import { installFocusDetector } from "../../utils/focusDetector.mjs";
20
22
  export const PLUGIN_KEY = 'pagination';
21
23
  export const PLUGIN_PRIORITY = 900;
24
+ const SHORTCUTS_GROUP = PLUGIN_KEY;
25
+ const SHORTCUTS_CONTEXT_NAME = `plugin:${PLUGIN_KEY}`;
22
26
  const AUTO_PAGE_SIZE_WARNING = toSingleLine`The \`auto\` page size setting requires the \`autoRowSize\`\x20
23
27
  plugin to be enabled. Set the \`autoRowSize: true\` in the configuration to ensure correct behavior.`;
24
28
 
@@ -103,13 +107,15 @@ var _ui = /*#__PURE__*/new WeakMap();
103
107
  var _calcStrategy = /*#__PURE__*/new WeakMap();
104
108
  var _internalExecutionCall = /*#__PURE__*/new WeakMap();
105
109
  var _internalRenderCall = /*#__PURE__*/new WeakMap();
110
+ var _focusController = /*#__PURE__*/new WeakMap();
111
+ var _focusDetector = /*#__PURE__*/new WeakMap();
106
112
  var _Pagination_brand = /*#__PURE__*/new WeakSet();
107
113
  var _onIndexCacheUpdate = /*#__PURE__*/new WeakMap();
108
114
  export class Pagination extends BasePlugin {
109
115
  constructor() {
110
116
  super(...arguments);
111
117
  /**
112
- * Updates the visibility state of the pagination sections based on the current settings.
118
+ * Bind the events used by the plugin.
113
119
  */
114
120
  _classPrivateMethodInitSpec(this, _Pagination_brand);
115
121
  /**
@@ -159,6 +165,18 @@ export class Pagination extends BasePlugin {
159
165
  * @type {boolean}
160
166
  */
161
167
  _classPrivateFieldInitSpec(this, _internalRenderCall, false);
168
+ /**
169
+ * Pagination focus controller instance.
170
+ *
171
+ * @type {PaginationController}
172
+ */
173
+ _classPrivateFieldInitSpec(this, _focusController, null);
174
+ /**
175
+ * Pagination focus detector instance.
176
+ *
177
+ * @type {object}
178
+ */
179
+ _classPrivateFieldInitSpec(this, _focusDetector, null);
162
180
  /**
163
181
  * IndexMapper cache update listener. Once the cache is updated, we need to recompute
164
182
  * the pagination state.
@@ -227,7 +245,7 @@ export class Pagination extends BasePlugin {
227
245
  _classPrivateFieldSet(_calcStrategy, this, createPaginatorStrategy(_classPrivateFieldGet(_pageSize, this) === 'auto' ? 'auto' : 'fixed'));
228
246
  if (!_classPrivateFieldGet(_ui, this)) {
229
247
  _classPrivateFieldSet(_ui, this, new PaginationUI({
230
- rootElement: this.hot.rootElement,
248
+ rootElement: this.hot.rootGridElement,
231
249
  uiContainer: this.getSetting('uiContainer'),
232
250
  isRtl: this.hot.isRtl(),
233
251
  themeName: this.hot.getSettings().themeName,
@@ -238,8 +256,35 @@ export class Pagination extends BasePlugin {
238
256
  a11yAnnouncer: message => announce(message)
239
257
  }));
240
258
  _assertClassBrand(_Pagination_brand, this, _updateSectionsVisibilityState).call(this);
241
- _classPrivateFieldGet(_ui, this).addLocalHook('firstPageClick', () => this.firstPage()).addLocalHook('prevPageClick', () => this.prevPage()).addLocalHook('nextPageClick', () => this.nextPage()).addLocalHook('lastPageClick', () => this.lastPage()).addLocalHook('pageSizeChange', pageSize => this.setPageSize(pageSize));
259
+ _classPrivateFieldGet(_ui, this).addLocalHook('firstPageClick', () => this.firstPage()).addLocalHook('prevPageClick', () => this.prevPage()).addLocalHook('nextPageClick', () => this.nextPage()).addLocalHook('lastPageClick', () => this.lastPage()).addLocalHook('pageSizeChange', pageSize => this.setPageSize(pageSize)).addLocalHook('focus', element => {
260
+ _classPrivateFieldGet(_focusController, this).setCurrentPage(_classPrivateFieldGet(_ui, this).getFocusableElements().indexOf(element));
261
+ this.hot.unlisten();
262
+ this.hot.getShortcutManager().setActiveContextName(SHORTCUTS_CONTEXT_NAME);
263
+ this.hot.listen();
264
+ _classPrivateFieldGet(_focusDetector, this).deactivate();
265
+ });
266
+ }
267
+ if (!_classPrivateFieldGet(_focusController, this)) {
268
+ _classPrivateFieldSet(_focusController, this, createPaginationFocusController({
269
+ focusableElements: () => _classPrivateFieldGet(_ui, this).getFocusableElements()
270
+ }));
242
271
  }
272
+ if (!_classPrivateFieldGet(_focusDetector, this)) {
273
+ _classPrivateFieldSet(_focusDetector, this, installFocusDetector(this.hot, _classPrivateFieldGet(_ui, this).getContainer(), {
274
+ onFocus: from => {
275
+ this.hot.getShortcutManager().setActiveContextName(SHORTCUTS_CONTEXT_NAME);
276
+ this.hot.listen();
277
+ if (from === 'from_above') {
278
+ _classPrivateFieldGet(_focusController, this).toFirstItem();
279
+ } else {
280
+ _classPrivateFieldGet(_focusController, this).toLastItem();
281
+ }
282
+ _classPrivateFieldGet(_focusDetector, this).deactivate();
283
+ }
284
+ }));
285
+ }
286
+ _assertClassBrand(_Pagination_brand, this, _registerEvents).call(this);
287
+ _assertClassBrand(_Pagination_brand, this, _registerShortcuts).call(this);
243
288
 
244
289
  // Place the onInit hook before others to make sure that the pagination state is computed
245
290
  // and applied to the index mapper before AutoColumnSize plugin begins calculate the column sizes.
@@ -321,6 +366,18 @@ export class Pagination extends BasePlugin {
321
366
  }
322
367
  return _assertClassBrand(_Pagination_brand, _this, _onAfterSetTheme).call(_this, ...args);
323
368
  });
369
+ this.addHook('afterDialogShow', function () {
370
+ for (var _len12 = arguments.length, args = new Array(_len12), _key12 = 0; _key12 < _len12; _key12++) {
371
+ args[_key12] = arguments[_key12];
372
+ }
373
+ return _assertClassBrand(_Pagination_brand, _this, _onAfterDialogShow).call(_this, ...args);
374
+ });
375
+ this.addHook('beforeDialogHide', function () {
376
+ for (var _len13 = arguments.length, args = new Array(_len13), _key13 = 0; _key13 < _len13; _key13++) {
377
+ args[_key13] = arguments[_key13];
378
+ }
379
+ return _assertClassBrand(_Pagination_brand, _this, _onAfterDialogHide).call(_this, ...args);
380
+ });
324
381
  this.hot.rowIndexMapper.addLocalHook('cacheUpdated', _classPrivateFieldGet(_onIndexCacheUpdate, this));
325
382
  super.enablePlugin();
326
383
  }
@@ -342,9 +399,9 @@ export class Pagination extends BasePlugin {
342
399
  this.hot.rowIndexMapper.removeLocalHook('cacheUpdated', _classPrivateFieldGet(_onIndexCacheUpdate, this)).unregisterMap(this.pluginName);
343
400
  _classPrivateFieldGet(_ui, this).destroy();
344
401
  _classPrivateFieldSet(_ui, this, null);
402
+ _assertClassBrand(_Pagination_brand, this, _unregisterShortcuts).call(this);
345
403
  super.disablePlugin();
346
404
  }
347
-
348
405
  /**
349
406
  * Gets the pagination current state. Returns an object with the following properties:
350
407
  * - `currentPage`: The current page number.
@@ -600,6 +657,11 @@ export class Pagination extends BasePlugin {
600
657
  _classPrivateFieldGet(_ui, this).setNavigationSectionVisibility(false);
601
658
  this.hot.runHooks('afterPageNavigationVisibilityChange', false);
602
659
  }
660
+
661
+ /**
662
+ * Updates the visibility state of the pagination sections based on the current settings.
663
+ */
664
+
603
665
  /**
604
666
  * Destroys the plugin instance.
605
667
  */
@@ -612,6 +674,59 @@ export class Pagination extends BasePlugin {
612
674
  super.destroy();
613
675
  }
614
676
  }
677
+ function _registerEvents() {
678
+ // TODO: move to general focus manager module
679
+ this.eventManager.addEventListener(this.hot.rootDocument, 'mouseup', event => {
680
+ const container = _classPrivateFieldGet(_ui, this).getContainer();
681
+ if (!container.contains(event.target) && this.hot.getShortcutManager().getActiveContextName() === SHORTCUTS_CONTEXT_NAME) {
682
+ _classPrivateFieldGet(_focusDetector, this).activate();
683
+ _classPrivateFieldGet(_focusController, this).clear();
684
+ this.hot.getShortcutManager().setActiveContextName('grid');
685
+ }
686
+ });
687
+ }
688
+ /**
689
+ * Register shortcuts responsible for navigating through the pagination.
690
+ */
691
+ function _registerShortcuts() {
692
+ var _manager$getContext;
693
+ const manager = this.hot.getShortcutManager();
694
+ const pluginContext = (_manager$getContext = manager.getContext(SHORTCUTS_CONTEXT_NAME)) !== null && _manager$getContext !== void 0 ? _manager$getContext : manager.addContext(SHORTCUTS_CONTEXT_NAME, 'global');
695
+ pluginContext.addShortcut({
696
+ keys: [['Shift', 'Tab'], ['Tab']],
697
+ preventDefault: false,
698
+ callback: event => {
699
+ let previousIndex = _classPrivateFieldGet(_focusController, this).getCurrentPage();
700
+ if (event.shiftKey) {
701
+ _classPrivateFieldGet(_focusController, this).toPreviousItem();
702
+ const currentPage = _classPrivateFieldGet(_focusController, this).getCurrentPage();
703
+ if (currentPage >= previousIndex) {
704
+ _assertClassBrand(_Pagination_brand, this, _unFocusPagination).call(this);
705
+ return;
706
+ }
707
+ previousIndex = currentPage;
708
+ } else {
709
+ _classPrivateFieldGet(_focusController, this).toNextItem();
710
+ const currentPage = _classPrivateFieldGet(_focusController, this).getCurrentPage();
711
+ if (currentPage <= previousIndex) {
712
+ _assertClassBrand(_Pagination_brand, this, _unFocusPagination).call(this);
713
+ return;
714
+ }
715
+ previousIndex = currentPage;
716
+ }
717
+ event.preventDefault();
718
+ },
719
+ group: SHORTCUTS_GROUP
720
+ });
721
+ }
722
+ /**
723
+ * Unregister shortcuts responsible for navigating through the pagination.
724
+ */
725
+ function _unregisterShortcuts() {
726
+ const shortcutManager = this.hot.getShortcutManager();
727
+ const pluginContext = shortcutManager.getContext(SHORTCUTS_CONTEXT_NAME);
728
+ pluginContext.removeShortcutsByGroup(SHORTCUTS_GROUP);
729
+ }
615
730
  function _updateSectionsVisibilityState() {
616
731
  if (this.getSetting('showPageSize')) {
617
732
  this.showPageSizeSection();
@@ -684,10 +799,16 @@ function _computeAndApplyState() {
684
799
  this.hot.rowIndexMapper.updateCache(true);
685
800
  }
686
801
  _classPrivateFieldSet(_internalExecutionCall, this, false);
802
+ const paginationData = this.getPaginationData();
687
803
  _classPrivateFieldGet(_ui, this).updateState({
688
- ...this.getPaginationData(),
804
+ ...paginationData,
689
805
  totalRenderedRows: renderableRowsLength
690
806
  });
807
+ if ((this.getSetting('showPageSize') || this.getSetting('showNavigation')) && paginationData.totalPages > 1) {
808
+ _classPrivateFieldGet(_focusDetector, this).activate();
809
+ } else {
810
+ _classPrivateFieldGet(_focusDetector, this).deactivate();
811
+ }
691
812
  }
692
813
  /**
693
814
  * Based on the external factors (like the scroll position of the table, size etc.) it computes
@@ -838,6 +959,24 @@ function _onAfterRender() {
838
959
  const width = view.isHorizontallyScrollableByWindow() ? view.getTotalTableWidth() : view.getWorkspaceWidth();
839
960
  _classPrivateFieldGet(_ui, this).updateWidth(width).refreshBorderState();
840
961
  }
962
+ /**
963
+ * Called before the height of the table is changed. It adjusts the table height to fit the pagination container
964
+ * in declared height.
965
+ *
966
+ * @param {number|string} height Table height.
967
+ * @returns {string} Returns the new table height.
968
+ */
969
+ function _onBeforeHeightChange(height) {
970
+ if (this.getSetting('uiContainer')) {
971
+ return height;
972
+ }
973
+ const isPixelValue = typeof height === 'number' || typeof height === 'string' && /^\d+$/.test(height) || typeof height === 'string' && height.endsWith('px');
974
+ if (!isPixelValue) {
975
+ return height;
976
+ }
977
+ const heightValue = typeof height === 'string' && height.endsWith('px') ? height : `${height}px`;
978
+ return `calc(${heightValue} - ${_classPrivateFieldGet(_ui, this).getHeight()}px)`;
979
+ }
841
980
  /**
842
981
  * Called after the initialization of the plugin. It computes the initial state of the pagination.
843
982
  */
@@ -860,19 +999,6 @@ function _onAfterScrollVertically() {
860
999
  function _onAfterLanguageChange() {
861
1000
  _assertClassBrand(_Pagination_brand, this, _computeAndApplyState).call(this);
862
1001
  }
863
- /**
864
- * Called before the height of the table is changed. It adjusts the table height to fit the pagination container
865
- * in declared height.
866
- *
867
- * @param {number} height Table height.
868
- * @returns {string} Returns the new table height.
869
- */
870
- function _onBeforeHeightChange(height) {
871
- if (this.getSetting('uiContainer')) {
872
- return height;
873
- }
874
- return `calc(${height}${/[0-9]$/.test(height) ? 'px' : ''} - ${_classPrivateFieldGet(_ui, this).getHeight()}px)`;
875
- }
876
1002
  /**
877
1003
  * Called after the theme is set. It updates the theme of the pagination container.
878
1004
  *
@@ -880,4 +1006,25 @@ function _onBeforeHeightChange(height) {
880
1006
  */
881
1007
  function _onAfterSetTheme(themeName) {
882
1008
  _classPrivateFieldGet(_ui, this).updateTheme(themeName);
1009
+ }
1010
+ /**
1011
+ * Unfocuses the pagination and sets the active context for the shortcuts.
1012
+ */
1013
+ function _unFocusPagination() {
1014
+ _classPrivateFieldGet(_focusDetector, this).activate();
1015
+ _classPrivateFieldGet(_focusController, this).clear();
1016
+ this.hot.unlisten();
1017
+ this.hot.getShortcutManager().setActiveContextName('grid');
1018
+ }
1019
+ /**
1020
+ * Called after the dialog is shown. It sets the active context for the shortcuts.
1021
+ */
1022
+ function _onAfterDialogShow() {
1023
+ _classPrivateFieldGet(_focusDetector, this).deactivate();
1024
+ }
1025
+ /**
1026
+ * Called after the dialog is hidden. It sets the active context for the shortcuts.
1027
+ */
1028
+ function _onAfterDialogHide() {
1029
+ _classPrivateFieldGet(_focusDetector, this).activate();
883
1030
  }