@revolist/revogrid 4.26.2 → 4.27.0

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 (118) hide show
  1. package/dist/cjs/{cell-renderer-Cf2Pu4S0.js → cell-renderer-C7rdgaov.js} +3 -3
  2. package/dist/cjs/{column.service-C7p5eC5V.js → column.service-Bbml5C2j.js} +3 -3
  3. package/dist/cjs/{dimension.helpers-CgHhnN1d.js → dimension.helpers-CptesQOZ.js} +52 -8
  4. package/dist/cjs/{edit.utils-rAcGublN.js → edit.utils-CBAbQhGP.js} +1 -1
  5. package/dist/cjs/{header-cell-renderer-DHClfIto.js → header-cell-renderer-BljFI6wj.js} +1 -1
  6. package/dist/cjs/{index--FdNLz1Z.js → index-BVESmpqW.js} +1 -1
  7. package/dist/cjs/index.cjs.js +71 -55
  8. package/dist/cjs/loader.cjs.js +1 -1
  9. package/dist/cjs/revo-grid.cjs.entry.js +74 -49
  10. package/dist/cjs/revo-grid.cjs.js +1 -1
  11. package/dist/cjs/revogr-attribution_7.cjs.entry.js +51 -19
  12. package/dist/cjs/revogr-clipboard_3.cjs.entry.js +4 -4
  13. package/dist/cjs/revogr-data_4.cjs.entry.js +21 -15
  14. package/dist/cjs/revogr-filter-panel.cjs.entry.js +9 -9
  15. package/dist/cjs/{column.drag.plugin-CK5HADlW.js → row-resize.plugin-BRQy_qNn.js} +573 -19
  16. package/dist/cjs/{text-editor-F04kTx53.js → text-editor-CJyQaYei.js} +2 -2
  17. package/dist/cjs/{throttle-fV6BUmM7.js → throttle-BsaP4fgu.js} +3 -3
  18. package/dist/cjs/{viewport.store-B4Clk4m9.js → viewport.store-mhsdi61t.js} +1 -1
  19. package/dist/collection/components/data/revogr-data-style.css +11 -0
  20. package/dist/collection/components/data/revogr-data.js +14 -8
  21. package/dist/collection/components/header/revogr-header-style.css +1 -0
  22. package/dist/collection/components/overlay/keyboard.service.js +33 -3
  23. package/dist/collection/components/overlay/revogr-overlay-selection.js +12 -10
  24. package/dist/collection/components/revoGrid/plugin.service.js +2 -2
  25. package/dist/collection/components/revoGrid/revo-grid.js +44 -10
  26. package/dist/collection/components/revoGrid/viewport.scrolling.service.js +24 -13
  27. package/dist/collection/components/revoGrid/viewport.service.js +1 -1
  28. package/dist/collection/plugins/filter/filter.constants.js +9 -0
  29. package/dist/collection/plugins/filter/filter.panel.js +8 -8
  30. package/dist/collection/plugins/filter/filter.plugin.js +109 -10
  31. package/dist/collection/plugins/filter/filter.style.css +2 -0
  32. package/dist/collection/plugins/groupingRow/grouping.row.plugin.js +9 -2
  33. package/dist/collection/plugins/groupingRow/grouping.row.renderer.js +1 -1
  34. package/dist/collection/plugins/groupingRow/grouping.service.js +1 -1
  35. package/dist/collection/plugins/index.js +1 -0
  36. package/dist/collection/plugins/row-resize/index.js +6 -0
  37. package/dist/collection/plugins/row-resize/row-resize.plugin.js +385 -0
  38. package/dist/collection/plugins/row-resize/row-resize.types.js +1 -0
  39. package/dist/collection/plugins/row-resize/row-resize.utils.js +55 -0
  40. package/dist/collection/serve/controller.js +1 -1
  41. package/dist/collection/services/data.provider.js +8 -2
  42. package/dist/collection/services/local.scroll.timer.js +3 -3
  43. package/dist/collection/services/selection.store.connector.js +4 -2
  44. package/dist/collection/store/dataSource/data.pending.plugin.js +21 -0
  45. package/dist/collection/store/dataSource/data.store.js +25 -3
  46. package/dist/collection/store/dataSource/trimmed.plugin.js +9 -6
  47. package/dist/collection/store/dimension/dimension.trim.plugin.js +1 -3
  48. package/dist/collection/types/events.js +4 -1
  49. package/dist/collection/utils/column.utils.js +1 -1
  50. package/dist/esm/{cell-renderer-11cf-lu3.js → cell-renderer-BFpmdV8H.js} +3 -3
  51. package/dist/esm/{column.service-Cfw3L0PN.js → column.service-CM-wgGs8.js} +3 -3
  52. package/dist/{revo-grid/dimension.helpers-fl4HSSK9.js → esm/dimension.helpers-Cln9sALu.js} +52 -9
  53. package/dist/{revo-grid/edit.utils-4e9fsqOR.js → esm/edit.utils-3ZbhQCv_.js} +1 -1
  54. package/dist/esm/{header-cell-renderer-Cqtg1ETB.js → header-cell-renderer-Bqh1PrgH.js} +1 -1
  55. package/dist/esm/{index-D24ku9ej.js → index-BvMNbQyq.js} +1 -1
  56. package/dist/esm/index.js +14 -11
  57. package/dist/esm/loader.js +1 -1
  58. package/dist/esm/revo-grid.entry.js +56 -31
  59. package/dist/esm/revo-grid.js +1 -1
  60. package/dist/esm/revogr-attribution_7.entry.js +51 -19
  61. package/dist/esm/revogr-clipboard_3.entry.js +4 -4
  62. package/dist/esm/revogr-data_4.entry.js +21 -15
  63. package/dist/esm/revogr-filter-panel.entry.js +9 -9
  64. package/dist/esm/{column.drag.plugin-DDBKeTGI.js → row-resize.plugin-BRiaHlHA.js} +562 -20
  65. package/dist/{revo-grid/text-editor-DlMnLkRK.js → esm/text-editor-eHtrwvxH.js} +2 -2
  66. package/dist/{revo-grid/throttle-Cpk1LoGk.js → esm/throttle-3rhqdcLy.js} +3 -3
  67. package/dist/{revo-grid/viewport.store-BSXmsiZc.js → esm/viewport.store-DWMKRDSH.js} +1 -1
  68. package/dist/revo-grid/{cell-renderer-11cf-lu3.js → cell-renderer-BFpmdV8H.js} +3 -3
  69. package/dist/revo-grid/{column.service-Cfw3L0PN.js → column.service-CM-wgGs8.js} +3 -3
  70. package/dist/{esm/dimension.helpers-fl4HSSK9.js → revo-grid/dimension.helpers-Cln9sALu.js} +52 -9
  71. package/dist/{esm/edit.utils-4e9fsqOR.js → revo-grid/edit.utils-3ZbhQCv_.js} +1 -1
  72. package/dist/revo-grid/{header-cell-renderer-Cqtg1ETB.js → header-cell-renderer-Bqh1PrgH.js} +1 -1
  73. package/dist/revo-grid/{index-D24ku9ej.js → index-BvMNbQyq.js} +1 -1
  74. package/dist/revo-grid/index.esm.js +14 -11
  75. package/dist/revo-grid/revo-grid.entry.js +56 -31
  76. package/dist/revo-grid/revo-grid.esm.js +1 -1
  77. package/dist/revo-grid/revogr-attribution_7.entry.js +51 -19
  78. package/dist/revo-grid/revogr-clipboard_3.entry.js +4 -4
  79. package/dist/revo-grid/revogr-data_4.entry.js +21 -15
  80. package/dist/revo-grid/revogr-filter-panel.entry.js +9 -9
  81. package/dist/revo-grid/{column.drag.plugin-DDBKeTGI.js → row-resize.plugin-BRiaHlHA.js} +562 -20
  82. package/dist/{esm/text-editor-DlMnLkRK.js → revo-grid/text-editor-eHtrwvxH.js} +2 -2
  83. package/dist/{esm/throttle-Cpk1LoGk.js → revo-grid/throttle-3rhqdcLy.js} +3 -3
  84. package/dist/{esm/viewport.store-BSXmsiZc.js → revo-grid/viewport.store-DWMKRDSH.js} +1 -1
  85. package/dist/types/components/data/revogr-data.d.ts +1 -0
  86. package/dist/types/components/overlay/keyboard.service.d.ts +6 -0
  87. package/dist/types/components/overlay/revogr-overlay-selection.d.ts +3 -1
  88. package/dist/types/components/revoGrid/revo-grid.d.ts +7 -1
  89. package/dist/types/components/revoGrid/viewport.scrolling.service.d.ts +3 -1
  90. package/dist/types/components.d.ts +23 -10
  91. package/dist/types/plugins/filter/filter.constants.d.ts +6 -0
  92. package/dist/types/plugins/filter/filter.plugin.d.ts +15 -0
  93. package/dist/types/plugins/index.d.ts +1 -0
  94. package/dist/types/plugins/row-resize/index.d.ts +3 -0
  95. package/dist/types/plugins/row-resize/row-resize.plugin.d.ts +44 -0
  96. package/dist/types/plugins/row-resize/row-resize.types.d.ts +40 -0
  97. package/dist/types/plugins/row-resize/row-resize.utils.d.ts +14 -0
  98. package/dist/types/services/data.provider.d.ts +2 -0
  99. package/dist/types/store/dataSource/data.pending.plugin.d.ts +9 -0
  100. package/dist/types/store/dataSource/data.store.d.ts +10 -0
  101. package/dist/types/store/dataSource/trimmed.plugin.d.ts +5 -0
  102. package/dist/types/types/events.d.ts +1 -1
  103. package/dist/types/types/interfaces.d.ts +3 -1
  104. package/hydrate/index.js +734 -85
  105. package/hydrate/index.mjs +734 -85
  106. package/package.json +1 -1
  107. package/readme.md +4 -1
  108. package/standalone/column.service.js +1 -1
  109. package/standalone/data.store.js +1 -1
  110. package/standalone/dimension.helpers.js +1 -1
  111. package/standalone/index.js +1 -1
  112. package/standalone/local.scroll.timer.js +1 -1
  113. package/standalone/revo-grid.js +1 -1
  114. package/standalone/revogr-data2.js +1 -1
  115. package/standalone/revogr-filter-panel.js +1 -1
  116. package/standalone/revogr-header2.js +1 -1
  117. package/standalone/revogr-overlay-selection2.js +1 -1
  118. package/standalone/revogr-row-headers2.js +1 -1
@@ -6,8 +6,9 @@ import { h } from "@stencil/core";
6
6
  import { BasePlugin } from "../base.plugin";
7
7
  import { FILTER_PROP, isFilterBtn } from "./filter.button";
8
8
  import { filterCoreFunctionsIndexedByType, filterNames, filterTypes, } from "./filter.indexed";
9
- import { timeout } from "../../utils";
10
9
  import { resolveBlankSemantics } from "./filter.blank";
10
+ import { timeout } from "../../utils";
11
+ import { ASYNC_FILTER_ROW_THRESHOLD, FILTER_CHUNK_SIZE, FILTER_TIME_BUDGET_MS, } from "./filter.constants";
11
12
  export * from './filter.types';
12
13
  export * from './filter.indexed';
13
14
  export * from './filter.blank';
@@ -55,6 +56,7 @@ export class FilterPlugin extends BasePlugin {
55
56
  this.filterFunctionsIndexedByType = Object.assign({}, filterCoreFunctionsIndexedByType);
56
57
  this.filterProp = FILTER_PROP;
57
58
  this.allowDuplicateOperators = true;
59
+ this.filteringRunId = 0;
58
60
  if (config) {
59
61
  this.initConfig(config);
60
62
  }
@@ -63,7 +65,7 @@ export class FilterPlugin extends BasePlugin {
63
65
  ...existingNodes,
64
66
  h("revogr-filter-panel", { filterNames: this.filterNameIndexByType, filterEntities: this.filterFunctionsIndexedByType, filterCaptions: (_a = config === null || config === void 0 ? void 0 : config.localization) === null || _a === void 0 ? void 0 : _a.captions, onFilterChange: e => this.onFilterChange(e.detail), onResetChange: e => this.onFilterReset(e.detail), disableDynamicFiltering: config === null || config === void 0 ? void 0 : config.disableDynamicFiltering, closeOnOutsideClick: config === null || config === void 0 ? void 0 : config.closeFilterPanelOnOutsideClick, allowDuplicateOperators: this.allowDuplicateOperators, ref: e => (this.pop = e) }, ' ', this.extraContent()),
65
67
  ];
66
- const aftersourceset = async () => {
68
+ const aftersourceset = () => {
67
69
  const filterCollectionProps = Object.keys(this.filterCollection);
68
70
  if (filterCollectionProps.length > 0) {
69
71
  // handle old way of filtering by reworking FilterCollection to new MultiFilterItem
@@ -80,12 +82,26 @@ export class FilterPlugin extends BasePlugin {
80
82
  }
81
83
  });
82
84
  }
83
- if (Object.keys(this.multiFilterItems).length === 0) {
85
+ if (!this.hasActiveFilters()) {
86
+ this.cancelFiltering();
84
87
  return;
85
88
  }
86
- await timeout();
87
- await this.runFiltering(this.multiFilterItems);
89
+ void this.runFiltering(this.multiFilterItems);
88
90
  };
91
+ /**
92
+ * This executes before the data store replaces its source.
93
+ * For a large source with active filters:
94
+ * 1. Existing filtering runs are invalidated.
95
+ * 2. Pending state starts.
96
+ * 3. Visible rows become empty.
97
+ * 4. The source is replaced while the DataStore guard prevents it from exposing unfiltered rows.
98
+ */
99
+ this.addEventListener('beforesourceset', ({ detail }) => {
100
+ if (detail.source.length >= ASYNC_FILTER_ROW_THRESHOLD &&
101
+ this.hasActiveFilters()) {
102
+ this.deferFiltering();
103
+ }
104
+ });
89
105
  this.addEventListener('headerclick', e => this.headerclick(e));
90
106
  this.addEventListener(FILTER_CONFIG_CHANGED_EVENT, ({ detail }) => {
91
107
  if (!detail) {
@@ -246,7 +262,7 @@ export class FilterPlugin extends BasePlugin {
246
262
  // store the filter items
247
263
  this.multiFilterItems = filterItems;
248
264
  // run the filtering when the items change
249
- this.runFiltering(this.multiFilterItems);
265
+ await this.runFiltering(this.multiFilterItems);
250
266
  }
251
267
  onFilterReset(prop) {
252
268
  delete this.multiFilterItems[prop !== null && prop !== void 0 ? prop : ''];
@@ -256,6 +272,8 @@ export class FilterPlugin extends BasePlugin {
256
272
  * Triggers grid filtering
257
273
  */
258
274
  async doFiltering(collection, source, columns, filterItems) {
275
+ // creates the execution token - owns the actual calculation
276
+ const runId = this.beginFiltering();
259
277
  const columnsToUpdate = [];
260
278
  /**
261
279
  * Loop through the columns and update the columns that need to be updated with the `hasFilter` property.
@@ -280,7 +298,25 @@ export class FilterPlugin extends BasePlugin {
280
298
  column[this.filterProp] = true;
281
299
  }
282
300
  });
283
- const itemsToTrim = this.getRowFilter(source, filterItems, columnByProp);
301
+ let itemsToTrim;
302
+ const hasFilters = Object.keys(filterItems).length > 0 || this.hasActiveFilters();
303
+ const isLargeSource = hasFilters && source.length >= ASYNC_FILTER_ROW_THRESHOLD;
304
+ if (isLargeSource) {
305
+ this.providers.data.setItemsPending(true);
306
+ await timeout();
307
+ }
308
+ if (!hasFilters) {
309
+ itemsToTrim = {};
310
+ }
311
+ else if (isLargeSource && this.supportsChunkedFiltering()) {
312
+ itemsToTrim = await this.getRowFilterInChunks(source, filterItems, columnByProp, runId);
313
+ }
314
+ else {
315
+ itemsToTrim = this.getRowFilter(source, filterItems, columnByProp);
316
+ }
317
+ if (!itemsToTrim || runId !== this.filteringRunId) {
318
+ return;
319
+ }
284
320
  // check is filter event prevented
285
321
  const { defaultPrevented, detail } = this.emit('beforefiltertrimmed', {
286
322
  collection,
@@ -288,10 +324,12 @@ export class FilterPlugin extends BasePlugin {
288
324
  source,
289
325
  filterItems,
290
326
  });
291
- if (defaultPrevented) {
327
+ if (defaultPrevented || runId !== this.filteringRunId) {
328
+ this.releaseFiltering(runId);
292
329
  return;
293
330
  }
294
331
  this.providers.data.setTrimmed({ [FILTER_TRIMMED_TYPE]: detail.itemsToFilter });
332
+ this.releaseFiltering(runId);
295
333
  // applies the hasFilter to the columns to show filter icon
296
334
  this.providers.column.updateColumns(columnsToUpdate);
297
335
  this.emit('afterfilterapply', {
@@ -305,6 +343,10 @@ export class FilterPlugin extends BasePlugin {
305
343
  await this.runFiltering(this.multiFilterItems);
306
344
  }
307
345
  async runFiltering(multiFilterItems) {
346
+ // runFiltering: First token: "Is this request still valid after event handlers run?"
347
+ // doFiltering: Second token: "Is this calculation still the newest one?"
348
+ // creates a preflight token and sets the grid to a pending state
349
+ const runId = this.beginFiltering();
308
350
  const collection = {};
309
351
  // handle old filterCollection to return the first filter only (if any) from multiFilterItems
310
352
  const filterProps = Object.keys(multiFilterItems);
@@ -328,10 +370,67 @@ export class FilterPlugin extends BasePlugin {
328
370
  columns,
329
371
  filterItems: this.multiFilterItems,
330
372
  });
331
- if (defaultPrevented) {
373
+ if (defaultPrevented || runId !== this.filteringRunId) {
374
+ this.releaseFiltering(runId);
332
375
  return;
333
376
  }
334
- this.doFiltering(detail.collection, detail.source, detail.columns, detail.filterItems);
377
+ await this.doFiltering(detail.collection, detail.source, detail.columns, detail.filterItems);
378
+ }
379
+ /** Whether this plugin currently owns filter state that must follow a new source. */
380
+ hasActiveFilters() {
381
+ return (Object.keys(this.multiFilterItems).length > 0 ||
382
+ Object.keys(this.filterCollection).length > 0);
383
+ }
384
+ /** Preserve whole-source semantics for plugins that override getRowFilter. */
385
+ supportsChunkedFiltering() {
386
+ return this.getRowFilter === FilterPlugin.prototype.getRowFilter;
387
+ }
388
+ /**
389
+ * Hide visible rows and invalidate current filtering until a deferred filter
390
+ * run is ready. Used by filter extensions with their own debounced state.
391
+ */
392
+ deferFiltering() {
393
+ this.beginFiltering(true);
394
+ }
395
+ beginFiltering(pending = false) {
396
+ const runId = ++this.filteringRunId;
397
+ if (pending) {
398
+ this.providers.data.setItemsPending(true);
399
+ }
400
+ return runId;
401
+ }
402
+ releaseFiltering(runId) {
403
+ if (runId === this.filteringRunId) {
404
+ this.providers.data.setItemsPending(false);
405
+ }
406
+ }
407
+ cancelFiltering() {
408
+ this.releaseFiltering(this.beginFiltering());
409
+ }
410
+ async getRowFilterInChunks(rows, filterItems, columnByProp, runId) {
411
+ const trimmed = {};
412
+ let sliceStarted = performance.now();
413
+ for (let offset = 0; offset < rows.length; offset += FILTER_CHUNK_SIZE) {
414
+ if (runId !== this.filteringRunId) {
415
+ return;
416
+ }
417
+ const end = Math.min(offset + FILTER_CHUNK_SIZE, rows.length);
418
+ const chunkTrimmed = this.getRowFilter(rows.slice(offset, end), filterItems, columnByProp);
419
+ // filter that chunk
420
+ for (const chunkIndex in chunkTrimmed) {
421
+ trimmed[offset + Number(chunkIndex)] = true;
422
+ }
423
+ if (end < rows.length &&
424
+ performance.now() - sliceStarted >= FILTER_TIME_BUDGET_MS) {
425
+ await timeout();
426
+ sliceStarted = performance.now();
427
+ }
428
+ }
429
+ return runId === this.filteringRunId ? trimmed : undefined;
430
+ }
431
+ destroy() {
432
+ this.cancelFiltering();
433
+ super.destroy();
335
434
  }
336
435
  /**
337
436
  * Get trimmed rows based on filter
@@ -127,6 +127,8 @@ revogr-filter-panel .filter-panel-dialog .filter-actions button {
127
127
  visibility: visible;
128
128
  cursor: pointer;
129
129
  border-radius: 4px;
130
+ position: relative;
131
+ z-index: 1;
130
132
  }
131
133
  .rgHeaderCell .rv-filter.active {
132
134
  color: var(--rg-theme-filter-panel-icon-active);
@@ -166,7 +166,7 @@ export class GroupingRowPlugin extends BasePlugin {
166
166
  customRenderer: options.groupLabelTemplate,
167
167
  cellRenderer: options.groupCellTemplate,
168
168
  });
169
- this.updateTrimmed(trimmed, oldNewIndexMap, undefined, sourceWithGroups);
169
+ this.updateTrimmed(trimmed, oldNewIndexMap, undefined, sourceWithGroups, { filterTrimmedMode: 'recompute-after-source-set' });
170
170
  }
171
171
  /**
172
172
  * External call to apply grouping. Called by revogrid when prop changed.
@@ -266,10 +266,17 @@ export class GroupingRowPlugin extends BasePlugin {
266
266
  this.providers.data.setData(source, GROUPING_ROW_TYPE, this.revogrid.disableVirtualY, undefined, true);
267
267
  this.updateTrimmed(undefined, undefined, oldNewIndexes, source);
268
268
  }
269
- updateTrimmed(trimmedGroup = {}, firstLevelMap = {}, secondLevelMap, source = this.getStore().get('source')) {
269
+ updateTrimmed(trimmedGroup = {}, firstLevelMap = {}, secondLevelMap, source = this.getStore().get('source'), { filterTrimmedMode = 'remap', } = {}) {
270
270
  // map previously trimmed data
271
271
  const trimemedOptionsToUpgrade = processDoubleConversionTrimmed(this.getStore().get('trimmed'), firstLevelMap, secondLevelMap);
272
272
  for (let type in trimemedOptionsToUpgrade) {
273
+ if (filterTrimmedMode === 'recompute-after-source-set' &&
274
+ type === FILTER_TRIMMED_TYPE) {
275
+ // The filter plugin recalculates this trim against the installed source
276
+ // during aftersourceset. Reapplying remapped old indexes afterwards
277
+ // would overwrite that fresh result.
278
+ continue;
279
+ }
273
280
  if (type === FILTER_TRIMMED_TYPE) {
274
281
  /** Regrouping changes physical indexes, so filter trim needs fresh group-header state. */
275
282
  trimemedOptionsToUpgrade[type] = filterOutEmptyGroupRows(source, trimemedOptionsToUpgrade[type]);
@@ -88,7 +88,7 @@ export const GroupingRowRenderer = (props) => {
88
88
  depth })))));
89
89
  }
90
90
  return (h(RowRenderer, Object.assign({}, props, groupRowAttrs), hasExpand && [
91
- h("button", { class: { [GROUP_EXPAND_BTN]: true }, onClick: e => expandEvent(e, model, itemIndex) }, expandSvgIconVNode(expanded)),
91
+ h("button", { type: "button", class: { [GROUP_EXPAND_BTN]: true }, onClick: e => expandEvent(e, model, itemIndex) }, expandSvgIconVNode(expanded)),
92
92
  String(name),
93
93
  ]));
94
94
  };
@@ -158,7 +158,7 @@ export function isGrouping(rgRow) {
158
158
  return typeof (rgRow === null || rgRow === void 0 ? void 0 : rgRow[PSEUDO_GROUP_ITEM]) !== 'undefined';
159
159
  }
160
160
  export function isGroupingColumn(column) {
161
- return typeof (column === null || column === void 0 ? void 0 : column[PSEUDO_GROUP_COLUMN]) !== 'undefined';
161
+ return (column === null || column === void 0 ? void 0 : column[PSEUDO_GROUP_COLUMN]) !== undefined;
162
162
  }
163
163
  export function measureEqualDepth(groupA, groupB) {
164
164
  const ln = groupA.length;
@@ -9,6 +9,7 @@ export * from './export/export.plugin';
9
9
  export * from './filter/filter.plugin';
10
10
  export * from './groupingRow/grouping.row.plugin';
11
11
  export * from './moveColumn/column.drag.plugin';
12
+ export * from './row-resize';
12
13
  export * from './sorting/sorting.plugin';
13
14
  export * from './sorting/sorting.sign';
14
15
  export * from './add-rows-on-paste.plugin';
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * Built by Revolist OU ❤️
3
+ */
4
+ export * from './row-resize.plugin';
5
+ export * from './row-resize.types';
6
+ export * from './row-resize.utils';
@@ -0,0 +1,385 @@
1
+ /*!
2
+ * Built by Revolist OU ❤️
3
+ */
4
+ import { getItemByIndex } from "../../store/index";
5
+ import { BasePlugin } from "../base.plugin";
6
+ import { GROUP_EXPAND_EVENT } from "../groupingRow/grouping.const";
7
+ import { clampRowResizeHeight, createRowResizePatch, getRowResizeIndexes, mergeRowResizeDefinitions, resolveRowResizeConfig, } from "./row-resize.utils";
8
+ export const ROW_RESIZE_HANDLE_CLASS = 'row-resize-handle';
9
+ export const BEFORE_ROW_RESIZE_EVENT = 'beforerowresize';
10
+ export const ROW_RESIZE_EVENT = 'rowresize';
11
+ export const AFTER_ROW_RESIZE_EVENT = 'afterrowresize';
12
+ export const ROW_RESIZE_CANCEL_EVENT = 'rowresizecancel';
13
+ export class RowResizePlugin extends BasePlugin {
14
+ static fromGridProperty(revogrid, providers) {
15
+ const plugin = new RowResizePlugin(revogrid, providers);
16
+ plugin.controlFromGridProperty();
17
+ return plugin;
18
+ }
19
+ constructor(revogrid, providers, config = {}) {
20
+ super(revogrid, providers);
21
+ this.enabled = false;
22
+ this.gridResizeRow = false;
23
+ this.gridPlugins = [];
24
+ this.committedSizes = new Map();
25
+ this.appliedIndexes = new Map();
26
+ this.previousBodyCursor = '';
27
+ this.decorateRow = ({ detail, }) => {
28
+ if (!this.enabled ||
29
+ (detail.colType !== 'rowHeaders' && !this.config.fullRow)) {
30
+ return;
31
+ }
32
+ const handle = this.h('div', {
33
+ 'key': `row-resize-${detail.rowType}-${detail.item.itemIndex}`,
34
+ 'class': { [ROW_RESIZE_HANDLE_CLASS]: true },
35
+ 'data-row-resize-index': detail.item.itemIndex,
36
+ 'aria-hidden': 'true',
37
+ 'onPointerDown': (event) => this.startResize(event, detail.rowType, detail.item.itemIndex),
38
+ });
39
+ detail.node.$children$ = [...(detail.node.$children$ || []), handle];
40
+ };
41
+ this.cancelForDataChange = () => this.cancel('data-change');
42
+ this.onPointerMove = (event) => {
43
+ const active = this.active;
44
+ if ((active === null || active === void 0 ? void 0 : active.pointerId) !== event.pointerId) {
45
+ return;
46
+ }
47
+ event.preventDefault();
48
+ active.lastEvent = event;
49
+ this.pendingHeight = clampRowResizeHeight(active.startHeight + event.clientY - active.startY, this.config);
50
+ if (this.animationFrame === undefined) {
51
+ const view = this.revogrid.ownerDocument.defaultView;
52
+ this.animationFrame = view === null || view === void 0 ? void 0 : view.requestAnimationFrame(() => {
53
+ this.animationFrame = undefined;
54
+ this.flushPendingResize();
55
+ });
56
+ }
57
+ };
58
+ this.onPointerUp = (event) => {
59
+ const active = this.active;
60
+ if ((active === null || active === void 0 ? void 0 : active.pointerId) !== event.pointerId) {
61
+ return;
62
+ }
63
+ event.preventDefault();
64
+ active.lastEvent = event;
65
+ this.pendingHeight = clampRowResizeHeight(active.startHeight + event.clientY - active.startY, this.config);
66
+ this.flushPendingResize();
67
+ if (this.active !== active) {
68
+ return;
69
+ }
70
+ const detail = this.eventDetail(active, event, active.currentHeight);
71
+ this.finishGesture();
72
+ this.commitResize(active);
73
+ this.emit(AFTER_ROW_RESIZE_EVENT, detail);
74
+ };
75
+ this.onPointerCancel = (event) => {
76
+ var _a;
77
+ if (((_a = this.active) === null || _a === void 0 ? void 0 : _a.pointerId) === event.pointerId) {
78
+ this.active.lastEvent = event;
79
+ this.cancel('pointercancel');
80
+ }
81
+ };
82
+ this.onKeyDown = (event) => {
83
+ if (event.key === 'Escape' && this.active) {
84
+ event.preventDefault();
85
+ this.cancel('escape');
86
+ }
87
+ };
88
+ this.onWindowBlur = () => this.cancel('blur');
89
+ this.reapplyCommittedSizes = () => this.applyCommittedSizes(false);
90
+ this.rebuildCommittedSizes = () => this.applyCommittedSizes(true);
91
+ this.syncAppliedIndexes = () => {
92
+ for (const [rowType, committed] of this.committedSizes) {
93
+ const items = this.providers.data.stores[rowType].store.get('items');
94
+ const indexes = new Set();
95
+ items.forEach((physicalIndex, virtualIndex) => {
96
+ if (committed.has(physicalIndex)) {
97
+ indexes.add(virtualIndex);
98
+ }
99
+ });
100
+ this.appliedIndexes.set(rowType, indexes);
101
+ }
102
+ };
103
+ this.config = resolveRowResizeConfig(config);
104
+ this.rowDefinitionsRef = revogrid.rowDefinitions;
105
+ if (new.target !== RowResizePlugin) {
106
+ this.enabled = true;
107
+ this.registerEventListeners();
108
+ }
109
+ }
110
+ registerEventListeners() {
111
+ this.addEventListener('beforerowrender', this.decorateRow);
112
+ this.addEventListener('beforeanysource', ({ detail }) => {
113
+ this.cancel('data-change');
114
+ const committed = this.committedSizes.get(detail.type);
115
+ if (!committed) {
116
+ return;
117
+ }
118
+ const removedIndexes = new Set();
119
+ for (const index of committed.keys()) {
120
+ if (index >= detail.source.length) {
121
+ committed.delete(index);
122
+ removedIndexes.add(index);
123
+ }
124
+ }
125
+ if (removedIndexes.size) {
126
+ const rowDefinitions = this.revogrid.rowDefinitions.filter(definition => definition.type !== detail.type ||
127
+ !removedIndexes.has(definition.index));
128
+ this.rowDefinitionsRef = rowDefinitions;
129
+ this.revogrid.rowDefinitions = rowDefinitions;
130
+ }
131
+ });
132
+ this.addEventListener('afteranysource', this.rebuildCommittedSizes);
133
+ this.addEventListener('beforesourcesortingapply', this.cancelForDataChange);
134
+ this.addEventListener('aftersortingapply', this.reapplyCommittedSizes);
135
+ this.addEventListener('beforefilterapply', this.cancelForDataChange);
136
+ this.addEventListener('beforerowdefinition', ({ detail }) => {
137
+ this.cancel('data-change');
138
+ if (detail.vals !== this.rowDefinitionsRef) {
139
+ this.committedSizes.clear();
140
+ this.appliedIndexes.clear();
141
+ this.rowDefinitionsRef = detail.vals;
142
+ }
143
+ });
144
+ this.addEventListener('afterthemechanged', this.reapplyCommittedSizes);
145
+ this.addEventListener('aftertrimmed', this.syncAppliedIndexes);
146
+ this.addEventListener('roworderchange', () => {
147
+ queueMicrotask(this.reapplyCommittedSizes);
148
+ });
149
+ this.addEventListener(GROUP_EXPAND_EVENT, () => {
150
+ queueMicrotask(this.reapplyCommittedSizes);
151
+ });
152
+ this.addEventListener('rowheaderschanged', ({ detail }) => {
153
+ if (!detail && !this.config.fullRow) {
154
+ this.cancel('row-headers-hidden');
155
+ }
156
+ });
157
+ }
158
+ controlFromGridProperty() {
159
+ this.gridResizeRow = this.revogrid.resizeRow;
160
+ this.gridPlugins = this.revogrid.plugins;
161
+ this.syncGridProperty(false);
162
+ this.watch('resizeRow', value => {
163
+ this.gridResizeRow = value;
164
+ this.syncGridProperty();
165
+ });
166
+ this.watch('plugins', value => {
167
+ this.gridPlugins = value || [];
168
+ this.syncGridProperty();
169
+ });
170
+ }
171
+ syncGridProperty(refresh = true) {
172
+ const hasConfiguredPlugin = this.gridPlugins.some(plugin => plugin !== RowResizePlugin &&
173
+ plugin.prototype instanceof RowResizePlugin);
174
+ const explicitlyEnabled = this.gridPlugins.includes(RowResizePlugin);
175
+ const enabled = hasConfiguredPlugin
176
+ ? false
177
+ : explicitlyEnabled || !!this.gridResizeRow;
178
+ const config = resolveRowResizeConfig(!hasConfiguredPlugin &&
179
+ !explicitlyEnabled &&
180
+ typeof this.gridResizeRow === 'object'
181
+ ? this.gridResizeRow
182
+ : undefined);
183
+ const configChanged = config.minHeight !== this.config.minHeight ||
184
+ config.maxHeight !== this.config.maxHeight ||
185
+ config.fullRow !== this.config.fullRow;
186
+ if (enabled === this.enabled && !configChanged) {
187
+ return;
188
+ }
189
+ this.cancel('config-change');
190
+ this.config = config;
191
+ if (enabled !== this.enabled) {
192
+ this.enabled = enabled;
193
+ if (enabled) {
194
+ this.rowDefinitionsRef = this.revogrid.rowDefinitions;
195
+ this.registerEventListeners();
196
+ }
197
+ else {
198
+ this.clearSubscriptions();
199
+ }
200
+ }
201
+ if (refresh) {
202
+ queueMicrotask(() => void this.revogrid.refresh());
203
+ }
204
+ }
205
+ startResize(event, rowType, index) {
206
+ var _a, _b;
207
+ if (!this.enabled ||
208
+ this.active ||
209
+ event.defaultPrevented ||
210
+ !event.isPrimary ||
211
+ (event.pointerType !== 'touch' && event.button !== 0)) {
212
+ return;
213
+ }
214
+ const dimension = this.providers.dimension.stores[rowType];
215
+ const dimensionState = dimension.getCurrentState();
216
+ const item = getItemByIndex(dimensionState, index);
217
+ const focusedStore = this.providers.selection.focusedStore;
218
+ const selectedRowType = focusedStore
219
+ ? this.providers.selection.storesYToType[focusedStore.position.y]
220
+ : undefined;
221
+ const indexes = getRowResizeIndexes({
222
+ rowType,
223
+ rowIndex: index,
224
+ rowCount: dimensionState.count,
225
+ selectedRange: this.providers.selection.selectedRange,
226
+ selectedRowType,
227
+ });
228
+ if (!indexes.length) {
229
+ return;
230
+ }
231
+ const previousSizes = indexes.reduce((sizes, rowIndex) => {
232
+ const row = getItemByIndex(dimensionState, rowIndex);
233
+ sizes[rowIndex] = row.end - row.start;
234
+ return sizes;
235
+ }, {});
236
+ const startHeight = item.end - item.start;
237
+ const active = {
238
+ pointerId: event.pointerId,
239
+ rowType,
240
+ index,
241
+ indexes,
242
+ startY: event.clientY,
243
+ startHeight,
244
+ currentHeight: startHeight,
245
+ previousSizes,
246
+ originalCustomSizes: Object.assign({}, dimensionState.sizes),
247
+ startEvent: event,
248
+ lastEvent: event,
249
+ };
250
+ const beforeEvent = this.emit(BEFORE_ROW_RESIZE_EVENT, this.eventDetail(active, event, startHeight));
251
+ if (beforeEvent.defaultPrevented) {
252
+ return;
253
+ }
254
+ event.preventDefault();
255
+ event.stopPropagation();
256
+ this.active = active;
257
+ const doc = this.revogrid.ownerDocument;
258
+ this.previousBodyCursor = ((_a = doc.body) === null || _a === void 0 ? void 0 : _a.style.cursor) || '';
259
+ if (doc.body) {
260
+ doc.body.style.cursor = 'row-resize';
261
+ }
262
+ doc.addEventListener('pointermove', this.onPointerMove, true);
263
+ doc.addEventListener('pointerup', this.onPointerUp, true);
264
+ doc.addEventListener('pointercancel', this.onPointerCancel, true);
265
+ doc.addEventListener('keydown', this.onKeyDown, true);
266
+ (_b = doc.defaultView) === null || _b === void 0 ? void 0 : _b.addEventListener('blur', this.onWindowBlur);
267
+ }
268
+ flushPendingResize() {
269
+ const active = this.active;
270
+ if (!active || this.pendingHeight === undefined) {
271
+ return;
272
+ }
273
+ const size = this.pendingHeight;
274
+ this.pendingHeight = undefined;
275
+ if (size === active.currentHeight) {
276
+ return;
277
+ }
278
+ this.providers.dimension.setCustomSizes(active.rowType, createRowResizePatch(active.indexes, size), true);
279
+ active.currentHeight = size;
280
+ this.emit(ROW_RESIZE_EVENT, this.eventDetail(active, active.lastEvent, size));
281
+ }
282
+ cancel(reason) {
283
+ const active = this.active;
284
+ if (!active) {
285
+ return;
286
+ }
287
+ const currentSizes = Object.assign({}, this.providers.dimension.stores[active.rowType].store.get('sizes'));
288
+ for (const index of active.indexes) {
289
+ if (Object.hasOwn(active.originalCustomSizes, index)) {
290
+ currentSizes[index] = active.originalCustomSizes[index];
291
+ }
292
+ else {
293
+ delete currentSizes[index];
294
+ }
295
+ }
296
+ this.providers.dimension.setCustomSizes(active.rowType, currentSizes);
297
+ const detail = Object.assign(Object.assign({}, this.eventDetail(active, active.lastEvent || active.startEvent, active.startHeight)), { reason });
298
+ this.finishGesture();
299
+ this.emit(ROW_RESIZE_CANCEL_EVENT, detail);
300
+ }
301
+ eventDetail(active, originalEvent, size) {
302
+ return {
303
+ rowType: active.rowType,
304
+ index: active.index,
305
+ indexes: [...active.indexes],
306
+ size,
307
+ previousSizes: Object.assign({}, active.previousSizes),
308
+ originalEvent,
309
+ };
310
+ }
311
+ commitResize(active) {
312
+ if (active.currentHeight === active.startHeight) {
313
+ return;
314
+ }
315
+ const items = this.providers.data.stores[active.rowType].store.get('items');
316
+ let committed = this.committedSizes.get(active.rowType);
317
+ if (!committed) {
318
+ committed = new Map();
319
+ this.committedSizes.set(active.rowType, committed);
320
+ }
321
+ let applied = this.appliedIndexes.get(active.rowType);
322
+ if (!applied) {
323
+ applied = new Set();
324
+ this.appliedIndexes.set(active.rowType, applied);
325
+ }
326
+ const physicalIndexes = active.indexes.reduce((result, index) => {
327
+ const physicalIndex = items[index];
328
+ if (physicalIndex !== undefined) {
329
+ committed.set(physicalIndex, active.currentHeight);
330
+ applied.add(index);
331
+ result.push(physicalIndex);
332
+ }
333
+ return result;
334
+ }, []);
335
+ if (physicalIndexes.length) {
336
+ const rowDefinitions = mergeRowResizeDefinitions(this.revogrid.rowDefinitions, active.rowType, physicalIndexes, active.currentHeight);
337
+ this.rowDefinitionsRef = rowDefinitions;
338
+ this.revogrid.rowDefinitions = rowDefinitions;
339
+ }
340
+ }
341
+ applyCommittedSizes(clearAppliedIndexes) {
342
+ for (const [rowType, committed] of this.committedSizes) {
343
+ const dimension = this.providers.dimension.stores[rowType];
344
+ const sizes = Object.assign({}, dimension.store.get('sizes'));
345
+ if (clearAppliedIndexes) {
346
+ for (const index of this.appliedIndexes.get(rowType) || []) {
347
+ delete sizes[index];
348
+ }
349
+ }
350
+ const items = this.providers.data.stores[rowType].store.get('items');
351
+ const indexes = new Set();
352
+ items.forEach((physicalIndex, virtualIndex) => {
353
+ const size = committed.get(physicalIndex);
354
+ if (size !== undefined) {
355
+ sizes[virtualIndex] = size;
356
+ indexes.add(virtualIndex);
357
+ }
358
+ });
359
+ this.appliedIndexes.set(rowType, indexes);
360
+ this.providers.dimension.setCustomSizes(rowType, sizes);
361
+ }
362
+ }
363
+ finishGesture() {
364
+ const doc = this.revogrid.ownerDocument;
365
+ const view = doc.defaultView;
366
+ if (this.animationFrame !== undefined) {
367
+ view === null || view === void 0 ? void 0 : view.cancelAnimationFrame(this.animationFrame);
368
+ }
369
+ doc.removeEventListener('pointermove', this.onPointerMove, true);
370
+ doc.removeEventListener('pointerup', this.onPointerUp, true);
371
+ doc.removeEventListener('pointercancel', this.onPointerCancel, true);
372
+ doc.removeEventListener('keydown', this.onKeyDown, true);
373
+ view === null || view === void 0 ? void 0 : view.removeEventListener('blur', this.onWindowBlur);
374
+ if (doc.body) {
375
+ doc.body.style.cursor = this.previousBodyCursor;
376
+ }
377
+ this.animationFrame = undefined;
378
+ this.pendingHeight = undefined;
379
+ this.active = undefined;
380
+ }
381
+ destroy() {
382
+ this.cancel('destroy');
383
+ super.destroy();
384
+ }
385
+ }