@highcharts/grid-pro 2.3.0 → 2.3.1

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 (54) hide show
  1. package/css/grid-pro.css +3 -3
  2. package/css/modules/grid-pro.css +1 -1
  3. package/es-modules/Accessibility/Components/ContainerComponent.js +0 -1
  4. package/es-modules/Accessibility/Components/InfoRegionsComponent.js +1 -2
  5. package/es-modules/Accessibility/Components/MenuComponent.js +0 -1
  6. package/es-modules/Accessibility/Components/RangeSelectorComponent.js +0 -1
  7. package/es-modules/Accessibility/Components/SeriesComponent/ForcedMarkers.js +21 -9
  8. package/es-modules/Accessibility/Components/SeriesComponent/NewDataAnnouncer.js +0 -3
  9. package/es-modules/Accessibility/Components/SeriesComponent/SeriesComponent.js +0 -1
  10. package/es-modules/Accessibility/Components/SeriesComponent/SeriesDescriber.js +0 -1
  11. package/es-modules/Accessibility/Components/SeriesComponent/SeriesKeyboardNavigation.js +0 -2
  12. package/es-modules/Accessibility/FocusBorder.js +5 -5
  13. package/es-modules/Accessibility/Options/DeprecatedOptions.js +1 -2
  14. package/es-modules/Accessibility/ProxyElement.d.ts +2 -2
  15. package/es-modules/Accessibility/ProxyElement.js +2 -2
  16. package/es-modules/Accessibility/Utils/ChartUtilities.js +0 -1
  17. package/es-modules/Accessibility/Utils/HTMLUtilities.js +0 -1
  18. package/es-modules/Core/Chart/Chart.js +8 -1
  19. package/es-modules/Core/Chart/ChartNavigationComposition.js +0 -1
  20. package/es-modules/Core/Chart/MapChart.js +2 -0
  21. package/es-modules/Core/Color/Color.js +0 -1
  22. package/es-modules/Core/Defaults.js +0 -1
  23. package/es-modules/Core/Delaunay.d.ts +0 -51
  24. package/es-modules/Core/Delaunay.js +5 -3
  25. package/es-modules/Core/Foundation.js +0 -1
  26. package/es-modules/Core/Globals.js +1 -1
  27. package/es-modules/Core/MSPointer.js +0 -1
  28. package/es-modules/Core/Renderer/HTML/HTMLAttributes.d.ts +3 -0
  29. package/es-modules/Core/Renderer/RendererUtilities.js +0 -1
  30. package/es-modules/Core/Renderer/SVG/SVGRenderer.d.ts +1 -1
  31. package/es-modules/Core/Renderer/SVG/Symbols.d.ts +2 -2
  32. package/es-modules/Core/Utilities.js +4 -2
  33. package/es-modules/Data/Connectors/DataConnector.d.ts +4 -4
  34. package/es-modules/Data/Connectors/DataConnector.js +4 -4
  35. package/es-modules/Data/DataPool.js +2 -2
  36. package/es-modules/Grid/Core/Globals.d.ts +2 -2
  37. package/es-modules/Grid/Core/Globals.js +1 -1
  38. package/es-modules/Grid/Core/Grid.js +4 -4
  39. package/es-modules/Grid/Core/Pagination/Pagination.js +5 -5
  40. package/es-modules/Grid/Core/Querying/PaginationController.d.ts +1 -1
  41. package/es-modules/Grid/Core/Querying/PaginationController.js +4 -3
  42. package/es-modules/Grid/Core/Responsive/ResponsiveComposition.js +53 -10
  43. package/es-modules/Grid/Core/Table/Actions/RowsVirtualizer.js +15 -1
  44. package/es-modules/Grid/Pro/Credits/CreditsProComposition.d.ts +1 -1
  45. package/es-modules/Grid/Pro/Data/DataSourceHelper.js +20 -10
  46. package/es-modules/Shared/Utilities.js +3 -11
  47. package/es-modules/masters/grid-pro.src.d.ts +3 -3
  48. package/es-modules/masters/grid-pro.src.js +1 -1
  49. package/grid-pro.d.ts +3 -3
  50. package/grid-pro.js +3 -3
  51. package/grid-pro.js.map +1 -1
  52. package/grid-pro.src.d.ts +3 -3
  53. package/grid-pro.src.js +117 -57
  54. package/package.json +1 -1
@@ -883,14 +883,14 @@ export class Grid {
883
883
  */
884
884
  async renderViewport() {
885
885
  const viewportMeta = this.viewport?.getStateMeta();
886
- const pagination = this.pagination;
887
- const paginationPosition = pagination?.options?.position;
888
- this.enabledColumns = await this.getEnabledColumnIDs();
889
886
  this.credits?.destroy();
890
887
  this.viewport?.destroy();
891
888
  delete this.viewport;
892
- this.resetContentWrapper();
893
889
  fireEvent(this, 'beforeRenderViewport');
890
+ this.resetContentWrapper();
891
+ this.enabledColumns = await this.getEnabledColumnIDs();
892
+ const pagination = this.pagination;
893
+ const paginationPosition = pagination?.options?.position;
894
894
  this.renderCaption();
895
895
  // Render top pagination if enabled (before table)
896
896
  if (paginationPosition === 'top') {
@@ -224,7 +224,7 @@ class Pagination {
224
224
  return;
225
225
  }
226
226
  const { currentPage, currentPageSize, totalItems, totalPages } = this.controller;
227
- const startItem = (currentPage - 1) * currentPageSize + 1;
227
+ const startItem = Math.min(Math.max(0, (currentPage - 1) * currentPageSize + 1), totalItems);
228
228
  const endItem = Math.min(currentPage * currentPageSize, totalItems);
229
229
  const pageInfoText = formatText(this.lang?.pageInfo ?? '', {
230
230
  start: startItem,
@@ -767,10 +767,10 @@ class Pagination {
767
767
  * Destroy the pagination instance.
768
768
  */
769
769
  destroy() {
770
- const position = this.options?.position;
771
- if (position === 'footer') {
772
- // For footer position, remove the entire tfoot element.
773
- this.paginationContainer?.parentElement?.parentElement?.remove();
770
+ // Fixed container removal when switching from custom to footer.
771
+ const tfoot = this.paginationContainer?.closest('tfoot');
772
+ if (tfoot) {
773
+ tfoot.remove();
774
774
  }
775
775
  else {
776
776
  this.contentWrapper?.remove();
@@ -40,7 +40,7 @@ declare class PaginationController {
40
40
  */
41
41
  get totalPages(): number;
42
42
  /**
43
- * Clamps the current page to the total number of pages.
43
+ * Clamps the current page to the valid range [1, totalPages].
44
44
  */
45
45
  clampPage(): void;
46
46
  /**
@@ -64,13 +64,14 @@ class PaginationController {
64
64
  return this.currentPageSize > 0 ? Math.ceil(this.totalItems / this.currentPageSize) : 1;
65
65
  }
66
66
  /**
67
- * Clamps the current page to the total number of pages.
67
+ * Clamps the current page to the valid range [1, totalPages].
68
68
  */
69
69
  clampPage() {
70
- if (this.currentPage <= this.totalPages) {
70
+ const target = Math.max(1, Math.min(this.currentPage, this.totalPages || 1));
71
+ if (this.currentPage === target) {
71
72
  return;
72
73
  }
73
- this.currentPage = this.totalPages;
74
+ this.currentPage = target;
74
75
  this.querying.shouldBeUpdated = true;
75
76
  }
76
77
  /**
@@ -43,14 +43,36 @@ export function compose(GridClass) {
43
43
  */
44
44
  function initResizeObserver() {
45
45
  destroyResizeObserver.call(this);
46
- if (!this.container) {
46
+ if (!this.container || !this.contentWrapper) {
47
47
  return;
48
48
  }
49
49
  this.activeRules = new Set();
50
+ // Synchronously evaluate responsive rules so the first render already
51
+ // uses the correct options (avoids a redundant second render).
52
+ if (!this.updatingResponsive) {
53
+ const rules = this.options?.responsive?.rules || [];
54
+ if (rules.length > 0) {
55
+ const { clientWidth: width, clientHeight: height } = this.container;
56
+ const fakeEntry = {
57
+ contentRect: { width, height }
58
+ };
59
+ const matchingRules = [];
60
+ for (const rule of rules) {
61
+ if (typeof rule._id === 'undefined') {
62
+ rule._id = uniqueKey();
63
+ }
64
+ if (matchResponsiveRule.call(this, rule, fakeEntry)) {
65
+ matchingRules.push(rule);
66
+ }
67
+ }
68
+ this.activeRules = new Set(matchingRules);
69
+ setResponsive.call(this, matchingRules, false);
70
+ }
71
+ }
50
72
  this.resizeObserver = new ResizeObserver((entries) => {
51
73
  onResize.call(this, entries[0]);
52
74
  });
53
- this.resizeObserver.observe(this.container);
75
+ this.resizeObserver.observe(this.contentWrapper);
54
76
  }
55
77
  /**
56
78
  * Destroys the resize observer.
@@ -90,20 +112,28 @@ function matchResponsiveRule(rule, entry) {
90
112
  *
91
113
  * @param matchingRules
92
114
  * Active responsive rules.
115
+ *
116
+ * @param redraw
117
+ * Whether to redraw the grid. Default is `true`.
93
118
  */
94
- function setResponsive(matchingRules) {
119
+ function setResponsive(matchingRules, redraw = true) {
95
120
  const ruleIds = matchingRules.map((rule) => rule._id);
96
121
  const ruleIdsString = (ruleIds.toString() || void 0);
97
122
  const currentRuleIds = this.currentResponsive?.ruleIds;
98
- if (ruleIdsString === currentRuleIds) {
123
+ if (ruleIdsString === currentRuleIds || this.updatingResponsive) {
99
124
  return;
100
125
  }
126
+ this.updatingResponsive = true;
127
+ let lastUpdate;
101
128
  if (this.currentResponsive) {
102
129
  const undoOptions = this.currentResponsive.undoOptions;
103
130
  this.currentResponsive = void 0;
104
- this.updatingResponsive = true;
105
- void this.update(undoOptions, true);
106
- this.updatingResponsive = false;
131
+ if (redraw) {
132
+ lastUpdate = this.update(undoOptions, true);
133
+ }
134
+ else {
135
+ this.update(undoOptions, false);
136
+ }
107
137
  }
108
138
  if (ruleIdsString) {
109
139
  const mergedOptions = merge(...matchingRules.map((rule) => rule.gridOptions));
@@ -120,10 +150,23 @@ function setResponsive(matchingRules) {
120
150
  mergedOptions,
121
151
  undoOptions
122
152
  };
123
- if (!this.updatingResponsive) {
124
- void this.update(mergedOptions, true);
153
+ if (redraw) {
154
+ lastUpdate = this.update(mergedOptions, true);
155
+ }
156
+ else {
157
+ this.update(mergedOptions, false);
125
158
  }
126
159
  }
160
+ // Keep the flag alive until the last queued update finishes so that
161
+ // ResizeObserver callbacks arriving in the meantime are ignored.
162
+ if (lastUpdate !== void 0) {
163
+ void lastUpdate.then(() => {
164
+ this.updatingResponsive = false;
165
+ });
166
+ }
167
+ else {
168
+ this.updatingResponsive = false;
169
+ }
127
170
  }
128
171
  /**
129
172
  * Builds undo options for columns by matching them by id.
@@ -203,7 +246,7 @@ function syncColumnIds(undoOptions, mergedOptions) {
203
246
  * The resize observer entry.
204
247
  */
205
248
  function onResize(entry) {
206
- if (!this.activeRules) {
249
+ if (!this.activeRules || this.updatingResponsive) {
207
250
  return;
208
251
  }
209
252
  const rules = this.options?.responsive?.rules || [];
@@ -210,8 +210,22 @@ class RowsVirtualizer {
210
210
  // Render missing rows, drop out-of-range ones, and ensure last row.
211
211
  await this.renderRows(this.rowCursor);
212
212
  const rows = this.viewport.rows;
213
+ // For non-virtualized rows, re-order rows to match data order.
214
+ if (!this.viewport.virtualRows) {
215
+ let node = tbody.firstElementChild;
216
+ for (let i = 0, iEnd = rows.length; i < iEnd; ++i) {
217
+ if (node === rows[i].htmlElement) {
218
+ node = node.nextElementSibling;
219
+ continue;
220
+ }
221
+ // Mismatch found, so append the rest in the correct order.
222
+ for (let j = i; j < iEnd; ++j) {
223
+ tbody.appendChild(rows[j].htmlElement);
224
+ }
225
+ break;
226
+ }
227
+ }
213
228
  for (let i = 0, iEnd = rows.length; i < iEnd; ++i) {
214
- // Update row data so indices map to fresh provider values.
215
229
  await rows[i].update();
216
230
  }
217
231
  if (this.viewport.virtualRows && defined(oldScrollTop)) {
@@ -13,7 +13,7 @@ declare module '../../Core/Options' {
13
13
  /**
14
14
  * Options for the credits label.
15
15
  *
16
- * Try it: {@link https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/grid-pro/credits | Credits options}
16
+ * Try it: {@link https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/grid-pro/basic/credits | Credits options}
17
17
  */
18
18
  credits?: CreditsOptions;
19
19
  }
@@ -34,9 +34,11 @@ const filterOperatorMap = {
34
34
  '<': 'lessThan',
35
35
  '<=': 'lessThanOrEqualTo',
36
36
  contains: 'contains',
37
+ notContains: 'doesNotContain',
37
38
  startsWith: 'beginsWith',
38
39
  endsWith: 'endsWith',
39
- empty: 'empty'
40
+ empty: 'empty',
41
+ notEmpty: 'notEmpty'
40
42
  };
41
43
  /**
42
44
  * Recursively extracts filter conditions from the Grid's FilterCondition
@@ -56,21 +58,29 @@ function extractFilterConditions(condition, filterColumns = []) {
56
58
  return filterColumns;
57
59
  }
58
60
  if (condition.operator === 'and' || condition.operator === 'or') {
59
- // Logical condition - extract from nested conditions
60
61
  if (condition.conditions) {
61
62
  for (const subCondition of condition.conditions) {
62
63
  extractFilterConditions(subCondition, filterColumns);
63
64
  }
64
65
  }
65
66
  }
66
- else if (condition.columnId) {
67
- // Single condition
68
- const mappedOperator = filterOperatorMap[condition.operator] || condition.operator;
69
- filterColumns.push({
70
- id: condition.columnId,
71
- condition: mappedOperator,
72
- value: condition.value
73
- });
67
+ else if (condition.columnId || condition.condition?.columnId) {
68
+ const conditionToUse = condition.columnId ?
69
+ condition : condition.condition;
70
+ let key = conditionToUse.operator;
71
+ if (condition.operator === 'not') {
72
+ key = condition.operator +
73
+ conditionToUse.operator.charAt(0).toUpperCase() +
74
+ conditionToUse.operator.slice(1);
75
+ }
76
+ const mapped = filterOperatorMap[key] || conditionToUse.operator;
77
+ if (conditionToUse.columnId) {
78
+ filterColumns.push({
79
+ id: conditionToUse.columnId,
80
+ condition: mapped,
81
+ value: conditionToUse.value
82
+ });
83
+ }
74
84
  }
75
85
  return filterColumns;
76
86
  }
@@ -9,7 +9,6 @@
9
9
  * */
10
10
  import H from '../Core/Globals.js';
11
11
  const { doc, win } = H;
12
- /* eslint-disable valid-jsdoc */
13
12
  /**
14
13
  * Add an event listener.
15
14
  *
@@ -35,7 +34,6 @@ const { doc, win } = H;
35
34
  * A callback function to remove the added event.
36
35
  */
37
36
  export function addEvent(el, type, fn, options = {}) {
38
- /* eslint-enable valid-jsdoc */
39
37
  // Add hcEvents to either the prototype (in case we're running addEvent on a
40
38
  // class) or the instance. If hasOwnProperty('hcEvents') is false, it is
41
39
  // inherited down the prototype chain, in which case we need to set the
@@ -434,7 +432,6 @@ export function erase(arr, item) {
434
432
  * Object a, the original object.
435
433
  */
436
434
  export function extend(a, b) {
437
- /* eslint-enable valid-jsdoc */
438
435
  let n;
439
436
  if (!a) {
440
437
  a = {};
@@ -467,7 +464,6 @@ export function extendClass(parent, members) {
467
464
  extend(obj.prototype, members);
468
465
  return obj;
469
466
  }
470
- /* eslint-disable valid-jsdoc */
471
467
  /**
472
468
  * Fire an event that was registered with {@link Highcharts#addEvent}.
473
469
  *
@@ -491,7 +487,6 @@ export function extendClass(parent, members) {
491
487
  * @return {void}
492
488
  */
493
489
  export function fireEvent(el, type, eventArguments, defaultFunction) {
494
- /* eslint-enable valid-jsdoc */
495
490
  eventArguments = eventArguments || {};
496
491
  if (doc?.createEvent &&
497
492
  (el.dispatchEvent ||
@@ -628,7 +623,7 @@ export function getMagnitude(num) {
628
623
  * @param {string} path
629
624
  * Path to the property, for example `custom.myValue`.
630
625
  *
631
- * @param {unknown} obj
626
+ * @param {unknown} parent
632
627
  * Instance containing the property on the specific path.
633
628
  *
634
629
  * @return {unknown}
@@ -1002,7 +997,6 @@ export function normalizeTickInterval(interval, multiples, magnitude, allowDecim
1002
997
  retInterval = correctFloat(retInterval * magnitude, -Math.round(Math.log(0.001) / Math.LN10));
1003
998
  return retInterval;
1004
999
  }
1005
- /* eslint-disable valid-jsdoc */
1006
1000
  /**
1007
1001
  * Iterate over object key pairs in an object.
1008
1002
  *
@@ -1021,7 +1015,6 @@ export function normalizeTickInterval(interval, multiples, magnitude, allowDecim
1021
1015
  * The context.
1022
1016
  */
1023
1017
  export function objectEach(obj, fn, ctx) {
1024
- /* eslint-enable valid-jsdoc */
1025
1018
  for (const key in obj) {
1026
1019
  if (Object.hasOwnProperty.call(obj, key)) {
1027
1020
  fn.call(ctx || obj[key], obj[key], key, obj);
@@ -1077,7 +1070,7 @@ export function pad(number, length, padder) {
1077
1070
  .replace('-', '')
1078
1071
  .length).join(padder || '0') + number;
1079
1072
  }
1080
- /* eslint-disable valid-jsdoc */
1073
+ /* eslint-disable jsdoc/check-param-names */
1081
1074
  /**
1082
1075
  * Return the first value that is not null or undefined.
1083
1076
  *
@@ -1099,6 +1092,7 @@ export function pick() {
1099
1092
  }
1100
1093
  }
1101
1094
  }
1095
+ /* eslint-enable jsdoc/check-param-names */
1102
1096
  /**
1103
1097
  * Shortcut for parseInt
1104
1098
  *
@@ -1187,7 +1181,6 @@ export function replaceNested(text, ...replacements) {
1187
1181
  } while (text !== previous);
1188
1182
  return text;
1189
1183
  }
1190
- /* eslint-disable valid-jsdoc */
1191
1184
  /**
1192
1185
  * Remove an event that was added with {@link Highcharts#addEvent}.
1193
1186
  *
@@ -1207,7 +1200,6 @@ export function replaceNested(text, ...replacements) {
1207
1200
  * @return {void}
1208
1201
  */
1209
1202
  export function removeEvent(el, type, fn) {
1210
- /* eslint-enable valid-jsdoc */
1211
1203
  /** @internal */
1212
1204
  function removeOneEvent(type, fn) {
1213
1205
  const removeEventListener = el.removeEventListener;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts Grid Pro v2.3.0 (2026-03-12)
2
+ * @license Highcharts Grid Pro v2.3.1 (2026-03-24)
3
3
  * @module grid/grid-pro
4
4
  *
5
5
  * (c) 2009-2026 Highsoft AS
@@ -112,11 +112,11 @@ declare const G: {
112
112
  helpers: Record<string, Function>;
113
113
  numberFormat: (this: Templating.Owner | void, number: number, decimals: number, decimalPoint?: string, thousandsSep?: string) => string;
114
114
  };
115
- readonly version: "2.3.0";
115
+ readonly version: "2.3.1";
116
116
  readonly win: Window & typeof globalThis;
117
117
  };
118
118
  export { AST, CellContentPro, CellRenderer, CellRendererRegistry, Column, ColumnResizing, DataConnector, DataConverter, DataCursor, DataModifier, DataProviderRegistry, DataPool, DataTable, _Grid as Grid, HeaderCell, _Options as Options, Pagination, Popup, SvgIcons, Table, TableCell, Templating };
119
- export declare const classNamePrefix: string, defaultOptions: import("../Shared/Types").DeepPartial<_Options>, grid: typeof _Grid.grid, grids: (_Grid | undefined)[], isHighContrastModeActive: () => boolean, product: "Grid Pro", setOptions: typeof import("../Grid/Core/Defaults.js").setOptions, version: "2.3.0", win: Window & typeof globalThis;
119
+ export declare const classNamePrefix: string, defaultOptions: import("../Shared/Types").DeepPartial<_Options>, grid: typeof _Grid.grid, grids: (_Grid | undefined)[], isHighContrastModeActive: () => boolean, product: "Grid Pro", setOptions: typeof import("../Grid/Core/Defaults.js").setOptions, version: "2.3.1", win: Window & typeof globalThis;
120
120
  declare namespace G {
121
121
  type Options = _Options;
122
122
  }
@@ -1,6 +1,6 @@
1
1
  // SPDX-License-Identifier: LicenseRef-Highcharts
2
2
  /**
3
- * @license Highcharts Grid Pro v2.3.0 (2026-03-12)
3
+ * @license Highcharts Grid Pro v2.3.1 (2026-03-24)
4
4
  * @module grid/grid-pro
5
5
  *
6
6
  * (c) 2009-2026 Highsoft AS
package/grid-pro.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts Grid Pro v2.3.0 (2026-03-12)
2
+ * @license Highcharts Grid Pro v2.3.1 (2026-03-24)
3
3
  * @module grid/grid-pro
4
4
  *
5
5
  * (c) 2009-2026 Highsoft AS
@@ -112,11 +112,11 @@ declare const G: {
112
112
  helpers: Record<string, Function>;
113
113
  numberFormat: (this: Templating.Owner | void, number: number, decimals: number, decimalPoint?: string, thousandsSep?: string) => string;
114
114
  };
115
- readonly version: "2.3.0";
115
+ readonly version: "2.3.1";
116
116
  readonly win: Window & typeof globalThis;
117
117
  };
118
118
  export { AST, CellContentPro, CellRenderer, CellRendererRegistry, Column, ColumnResizing, DataConnector, DataConverter, DataCursor, DataModifier, DataProviderRegistry, DataPool, DataTable, _Grid as Grid, HeaderCell, _Options as Options, Pagination, Popup, SvgIcons, Table, TableCell, Templating };
119
- export declare const classNamePrefix: string, defaultOptions: import("./es-modules/Shared/Types").DeepPartial<_Options>, grid: typeof _Grid.grid, grids: (_Grid | undefined)[], isHighContrastModeActive: () => boolean, product: "Grid Pro", setOptions: typeof import("./es-modules/Grid/Core/Defaults.js").setOptions, version: "2.3.0", win: Window & typeof globalThis;
119
+ export declare const classNamePrefix: string, defaultOptions: import("./es-modules/Shared/Types").DeepPartial<_Options>, grid: typeof _Grid.grid, grids: (_Grid | undefined)[], isHighContrastModeActive: () => boolean, product: "Grid Pro", setOptions: typeof import("./es-modules/Grid/Core/Defaults.js").setOptions, version: "2.3.1", win: Window & typeof globalThis;
120
120
  declare namespace G {
121
121
  type Options = _Options;
122
122
  }