@revolist/revogrid 4.27.0 → 4.27.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 (55) hide show
  1. package/dist/cjs/{cell-renderer-C7rdgaov.js → cell-renderer-BDIx0xys.js} +1 -1
  2. package/dist/cjs/{column.service-Bbml5C2j.js → column.service-D-ENzqyb.js} +2 -0
  3. package/dist/cjs/{header-cell-renderer-BljFI6wj.js → header-cell-renderer-B5Y4fdZC.js} +1 -1
  4. package/dist/cjs/index.cjs.js +5 -4
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/revo-grid.cjs.entry.js +61 -41
  7. package/dist/cjs/revo-grid.cjs.js +1 -1
  8. package/dist/cjs/revogr-attribution_7.cjs.entry.js +1 -1
  9. package/dist/cjs/revogr-data_4.cjs.entry.js +3 -3
  10. package/dist/cjs/{row-resize.plugin-BRQy_qNn.js → row-resize.plugin-sK9_rcUN.js} +299 -180
  11. package/dist/collection/components/revoGrid/revo-grid.js +37 -21
  12. package/dist/collection/plugins/groupingRow/grouping.const.js +1 -0
  13. package/dist/collection/plugins/groupingRow/grouping.row.plugin.js +84 -54
  14. package/dist/collection/plugins/groupingRow/grouping.sorting.service.js +58 -0
  15. package/dist/collection/plugins/groupingRow/grouping.trimmed.service.js +5 -3
  16. package/dist/collection/plugins/row-resize/row-resize.plugin.js +144 -113
  17. package/dist/collection/plugins/sorting/sorting.plugin.js +16 -13
  18. package/dist/collection/plugins/wcag/index.js +5 -4
  19. package/dist/collection/services/dimension.provider.js +17 -1
  20. package/dist/esm/{cell-renderer-BFpmdV8H.js → cell-renderer-D9ze8OJw.js} +1 -1
  21. package/dist/esm/{column.service-CM-wgGs8.js → column.service-pu_fdQ0S.js} +2 -1
  22. package/dist/{revo-grid/header-cell-renderer-Bqh1PrgH.js → esm/header-cell-renderer-YCiVIQ2E.js} +1 -1
  23. package/dist/esm/index.js +5 -5
  24. package/dist/esm/loader.js +1 -1
  25. package/dist/esm/revo-grid.entry.js +61 -41
  26. package/dist/esm/revo-grid.js +1 -1
  27. package/dist/esm/revogr-attribution_7.entry.js +1 -1
  28. package/dist/esm/revogr-data_4.entry.js +3 -3
  29. package/dist/esm/{row-resize.plugin-BRiaHlHA.js → row-resize.plugin-DBOgjLdE.js} +300 -181
  30. package/dist/revo-grid/{cell-renderer-BFpmdV8H.js → cell-renderer-D9ze8OJw.js} +1 -1
  31. package/dist/revo-grid/{column.service-CM-wgGs8.js → column.service-pu_fdQ0S.js} +2 -1
  32. package/dist/{esm/header-cell-renderer-Bqh1PrgH.js → revo-grid/header-cell-renderer-YCiVIQ2E.js} +1 -1
  33. package/dist/revo-grid/index.esm.js +5 -5
  34. package/dist/revo-grid/revo-grid.entry.js +61 -41
  35. package/dist/revo-grid/revo-grid.esm.js +1 -1
  36. package/dist/revo-grid/revogr-attribution_7.entry.js +1 -1
  37. package/dist/revo-grid/revogr-data_4.entry.js +3 -3
  38. package/dist/revo-grid/{row-resize.plugin-BRiaHlHA.js → row-resize.plugin-DBOgjLdE.js} +300 -181
  39. package/dist/types/components/revoGrid/revo-grid.d.ts +2 -0
  40. package/dist/types/plugins/groupingRow/grouping.const.d.ts +1 -0
  41. package/dist/types/plugins/groupingRow/grouping.row.plugin.d.ts +5 -7
  42. package/dist/types/plugins/groupingRow/grouping.sorting.service.d.ts +7 -0
  43. package/dist/types/plugins/groupingRow/grouping.trimmed.service.d.ts +9 -0
  44. package/dist/types/plugins/row-resize/row-resize.plugin.d.ts +14 -12
  45. package/dist/types/plugins/sorting/sorting.plugin.d.ts +5 -0
  46. package/dist/types/services/dimension.provider.d.ts +7 -1
  47. package/hydrate/index.js +358 -218
  48. package/hydrate/index.mjs +358 -218
  49. package/package.json +1 -1
  50. package/standalone/column.service.js +1 -1
  51. package/standalone/index.js +1 -1
  52. package/standalone/revo-grid.js +1 -1
  53. package/standalone/revogr-data2.js +1 -1
  54. package/standalone/revogr-header2.js +1 -1
  55. package/standalone/revogr-overlay-selection2.js +1 -1
@@ -3,14 +3,14 @@
3
3
  */
4
4
  'use strict';
5
5
 
6
- var column_service = require('./column.service-Bbml5C2j.js');
6
+ var column_service = require('./column.service-D-ENzqyb.js');
7
7
  var dimension_helpers = require('./dimension.helpers-CptesQOZ.js');
8
8
  var viewport_store = require('./viewport.store-mhsdi61t.js');
9
9
  var index$1 = require('./index-BVESmpqW.js');
10
10
  var index = require('./index-DRvxCueo.js');
11
11
  var filter_button = require('./filter.button-F2Bw3UAd.js');
12
12
  var debounce = require('./debounce-CcpHiH2p.js');
13
- var headerCellRenderer = require('./header-cell-renderer-BljFI6wj.js');
13
+ var headerCellRenderer = require('./header-cell-renderer-B5Y4fdZC.js');
14
14
 
15
15
  /**
16
16
  * Public theme tokens and their CSS custom-property counterparts.
@@ -1909,6 +1909,60 @@ function allAndConditionsSatisfied(pendingResults) {
1909
1909
  return !pendingResults.includes(true);
1910
1910
  }
1911
1911
 
1912
+ /**
1913
+ * Restores group headers around already-sorted data indexes without rebuilding
1914
+ * the physical source. Group insertion order follows the first sorted member,
1915
+ * matching the order produced by regrouping a sorted source.
1916
+ */
1917
+ function gatherGroupedRowIndexes(source, sortedDataIndexes) {
1918
+ const groupPathByDataIndex = new Map();
1919
+ const currentGroupPath = [];
1920
+ source.forEach((model, physicalIndex) => {
1921
+ if (column_service.isGrouping(model)) {
1922
+ const depth = model[column_service.GROUP_DEPTH];
1923
+ if (typeof depth !== 'number') {
1924
+ return;
1925
+ }
1926
+ currentGroupPath.length = depth;
1927
+ currentGroupPath[depth] = physicalIndex;
1928
+ return;
1929
+ }
1930
+ if (model != null) {
1931
+ groupPathByDataIndex.set(physicalIndex, [...currentGroupPath]);
1932
+ }
1933
+ });
1934
+ const root = {
1935
+ children: new Map(),
1936
+ items: [],
1937
+ };
1938
+ for (const physicalIndex of sortedDataIndexes) {
1939
+ const groupPath = groupPathByDataIndex.get(physicalIndex);
1940
+ if (!(groupPath === null || groupPath === void 0 ? void 0 : groupPath.length)) {
1941
+ return undefined;
1942
+ }
1943
+ let node = root;
1944
+ for (const groupIndex of groupPath) {
1945
+ let child = node.children.get(groupIndex);
1946
+ if (!child) {
1947
+ child = { children: new Map(), items: [] };
1948
+ node.children.set(groupIndex, child);
1949
+ }
1950
+ node = child;
1951
+ }
1952
+ node.items.push(physicalIndex);
1953
+ }
1954
+ const groupedIndexes = [];
1955
+ const appendNode = (node) => {
1956
+ node.children.forEach((child, groupIndex) => {
1957
+ groupedIndexes.push(groupIndex);
1958
+ appendNode(child);
1959
+ });
1960
+ groupedIndexes.push(...node.items);
1961
+ };
1962
+ appendNode(root);
1963
+ return groupedIndexes;
1964
+ }
1965
+
1912
1966
  /**
1913
1967
  * Checks whether a sorting map contains at least one active order.
1914
1968
  *
@@ -2146,18 +2200,6 @@ function getComparer(column, order) {
2146
2200
  function getSortableRowIndexes(indexes, source) {
2147
2201
  return indexes.filter(index => !column_service.isGrouping(source[index]));
2148
2202
  }
2149
- function mergeSortedRowsWithGroups(indexes, source, sortedRows) {
2150
- if (sortedRows.length === indexes.length) {
2151
- return sortedRows;
2152
- }
2153
- let rowIndex = 0;
2154
- return indexes.map(index => {
2155
- if (column_service.isGrouping(source[index])) {
2156
- return index;
2157
- }
2158
- return sortedRows[rowIndex++];
2159
- });
2160
- }
2161
2203
  /**
2162
2204
  * Lifecycle
2163
2205
  * 1. @event `beforesorting` - Triggered when sorting just starts. Nothing has happened yet. This can be triggered from a column or from the source. If the type is from rows, the column will be undefined.
@@ -2317,6 +2359,7 @@ class SortingPlugin extends BasePlugin {
2317
2359
  storeService.setData({ proxyItems: newItemsOrder });
2318
2360
  }
2319
2361
  applySortingForStore(type, sorting, sortingFunc, sortingColumns, sortingOrder, ignoreViewportUpdate) {
2362
+ var _a;
2320
2363
  const storeService = this.providers.data.stores[type];
2321
2364
  // row data
2322
2365
  const source = storeService.store.get('source');
@@ -2324,7 +2367,10 @@ class SortingPlugin extends BasePlugin {
2324
2367
  const proxyItems = storeService.store.get('proxyItems');
2325
2368
  const sortItems = getSortableRowIndexes(proxyItems, source);
2326
2369
  const sortedItems = sortIndexByItems([...sortItems], source, sortingFunc, sorting, sortingColumns, sortingOrder);
2327
- const newItemsOrder = mergeSortedRowsWithGroups(proxyItems, source, sortedItems);
2370
+ const hasGroupingRows = sortedItems.length !== proxyItems.length;
2371
+ const newItemsOrder = hasGroupingRows
2372
+ ? (_a = gatherGroupedRowIndexes(source, sortedItems)) !== null && _a !== void 0 ? _a : proxyItems
2373
+ : sortedItems;
2328
2374
  // take row indexes before trim applied and proxy items
2329
2375
  const prevItems = storeService.store.get('items');
2330
2376
  storeService.setData({
@@ -2350,6 +2396,16 @@ class SortingPlugin extends BasePlugin {
2350
2396
  }
2351
2397
  this.postponeSort(order, sortingFunc, sortingColumns, sortingOrder, ignoreViewportUpdate);
2352
2398
  }
2399
+ /**
2400
+ * Schedules the current active sort again after another plugin rebuilds row
2401
+ * proxy indexes while keeping the physical source unchanged.
2402
+ */
2403
+ reapplySorting() {
2404
+ if (!hasActiveSorting(this.sorting) || !this.sortingFunc) {
2405
+ return;
2406
+ }
2407
+ this.startSorting(this.sorting, this.sortingFunc, this.sortingColumns, this.sortingOrder);
2408
+ }
2353
2409
  /**
2354
2410
  * Applies sorting requested by a sortable header click.
2355
2411
  *
@@ -2533,8 +2589,10 @@ const TRIMMED_GROUPING = 'grouping';
2533
2589
  * against the grouped physical source can still be remapped. If neither path
2534
2590
  * resolves to a number, the caller drops the stale trim entry.
2535
2591
  */
2536
- function convertTrimmedIndex(initialIndex, firstLevelMap, secondLevelMap) {
2537
- const sourceIndex = Number.parseInt(initialIndex, 10);
2592
+ function convertGroupingIndex(initialIndex, firstLevelMap, secondLevelMap) {
2593
+ const sourceIndex = typeof initialIndex === 'number'
2594
+ ? initialIndex
2595
+ : Number.parseInt(initialIndex, 10);
2538
2596
  const firstConversionIndex = firstLevelMap[sourceIndex];
2539
2597
  if (!secondLevelMap) {
2540
2598
  return firstConversionIndex;
@@ -2567,7 +2625,7 @@ function processDoubleConversionTrimmed(initiallyTrimed, firstLevelMap, secondLe
2567
2625
  * if item exists we find it in collection
2568
2626
  * we support 2 level of conversions
2569
2627
  */
2570
- const newConversionIndex = convertTrimmedIndex(initialIndex, firstLevelMap, secondLevelMap);
2628
+ const newConversionIndex = convertGroupingIndex(initialIndex, firstLevelMap, secondLevelMap);
2571
2629
  // Group rows do not exist in the ungrouped index map and must not leak into new trims.
2572
2630
  if (typeof newConversionIndex !== 'number') {
2573
2631
  continue;
@@ -2628,18 +2686,6 @@ function filterOutEmptyGroupRows(source, filterTrimmed) {
2628
2686
  return trimmed;
2629
2687
  }
2630
2688
 
2631
- var __rest = (undefined && undefined.__rest) || function (s, e) {
2632
- var t = {};
2633
- for (var p in s)
2634
- if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
2635
- t[p] = s[p];
2636
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
2637
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
2638
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
2639
- t[p[i]] = s[p[i]];
2640
- }
2641
- return t;
2642
- };
2643
2689
  class GroupingRowPlugin extends BasePlugin {
2644
2690
  getStore(type = column_service.GROUPING_ROW_TYPE) {
2645
2691
  return this.providers.data.stores[type].store;
@@ -2655,15 +2701,16 @@ class GroupingRowPlugin extends BasePlugin {
2655
2701
  }
2656
2702
  // expand event triggered
2657
2703
  onExpand({ virtualIndex }) {
2658
- const { source } = column_service.getSource(this.getStore().get('source'), this.getStore().get('proxyItems'));
2659
- let newTrimmed = this.getStore().get('trimmed')[TRIMMED_GROUPING];
2660
- let i = dimension_helpers.getPhysical(this.getStore(), virtualIndex);
2704
+ const store = this.getStore();
2705
+ const source = store.get('source');
2706
+ let newTrimmed = store.get('trimmed')[TRIMMED_GROUPING];
2707
+ const i = dimension_helpers.getPhysical(store, virtualIndex);
2661
2708
  const isExpanded = column_service.getExpanded(source[i]);
2662
2709
  if (!isExpanded) {
2663
- const { trimmed, items } = doExpand(virtualIndex, source, this.getStore().get('items'));
2710
+ const { trimmed, items: expandedItems } = doExpand(virtualIndex, source, store.get('items'));
2664
2711
  newTrimmed = Object.assign(Object.assign({}, newTrimmed), trimmed);
2665
- if (items) {
2666
- dimension_helpers.setItems(this.getStore(), items);
2712
+ if (expandedItems) {
2713
+ dimension_helpers.setItems(store, expandedItems);
2667
2714
  }
2668
2715
  }
2669
2716
  else {
@@ -2671,7 +2718,7 @@ class GroupingRowPlugin extends BasePlugin {
2671
2718
  newTrimmed = Object.assign(Object.assign({}, newTrimmed), trimmed);
2672
2719
  this.revogrid.clearFocus();
2673
2720
  }
2674
- this.getStore().set('source', source);
2721
+ store.set('source', source);
2675
2722
  this.revogrid.addTrimmed(newTrimmed, TRIMMED_GROUPING);
2676
2723
  }
2677
2724
  setColumnGrouping(cols) {
@@ -2693,7 +2740,7 @@ class GroupingRowPlugin extends BasePlugin {
2693
2740
  onDrag(e) {
2694
2741
  const { from, to } = e.detail;
2695
2742
  const isDown = to - from >= 0;
2696
- const { source } = column_service.getSource(this.getStore().get('source'), this.getStore().get('proxyItems'));
2743
+ const source = this.getStore().get('source');
2697
2744
  const items = this.getStore().get('items');
2698
2745
  let i = isDown ? from : to;
2699
2746
  const end = isDown ? to : from;
@@ -2719,21 +2766,13 @@ class GroupingRowPlugin extends BasePlugin {
2719
2766
  const source = this.getStore().get('source');
2720
2767
  return filterOutEmptyGroupRows(source, trimmed);
2721
2768
  }
2722
- isSortingRunning() {
2723
- const sortingPlugin = this.providers.plugins.getByClass(SortingPlugin);
2724
- return !!(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sortingPromise);
2725
- }
2726
2769
  /**
2727
- * Returns grouping options for regrouping that must preserve current UI state.
2728
- *
2729
- * `expandedAll` and config `prevExpanded` are initial/config instructions.
2730
- * Reusing them after sorting would reopen groups the user collapsed before
2731
- * sorting instead of using the current grouped source state.
2770
+ * Sorting changes proxy order without changing the physical source baseline.
2771
+ * Other proxy changes, such as row dragging, are user-authored source order
2772
+ * and must be retained when grouping is rebuilt.
2732
2773
  */
2733
- getCurrentExpandedOptions() {
2734
- var _a;
2735
- const _b = (_a = this.options) !== null && _a !== void 0 ? _a : {}, options = __rest(_b, ["expandedAll", "prevExpanded"]);
2736
- return options;
2774
+ isSortingActiveOrPending(sortingPlugin) {
2775
+ return !!(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sortingPromise) || hasActiveSorting(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sorting);
2737
2776
  }
2738
2777
  /**
2739
2778
  * Starts global source update with group clearing and applying new one
@@ -2746,7 +2785,12 @@ class GroupingRowPlugin extends BasePlugin {
2746
2785
  * @param newOldIndexMap - provides us mapping with new indexes vs old indexes, we would use it for trimmed mapping
2747
2786
  */
2748
2787
  const store = this.getStore();
2749
- const { source, prevExpanded, oldNewIndexes } = column_service.getSource(store.get('source'), store.get('proxyItems'), true);
2788
+ const sortingPlugin = this.providers.plugins.getByClass(SortingPlugin);
2789
+ const currentSource = store.get('source');
2790
+ const sourceItems = this.isSortingActiveOrPending(sortingPlugin)
2791
+ ? currentSource.map((_, index) => index)
2792
+ : store.get('proxyItems');
2793
+ const { source, prevExpanded, oldNewIndexes } = column_service.getSource(currentSource, sourceItems, true);
2750
2794
  const expanded = Object.assign({ prevExpanded }, options);
2751
2795
  /**
2752
2796
  * Group again
@@ -2756,8 +2800,13 @@ class GroupingRowPlugin extends BasePlugin {
2756
2800
  const customRenderer = options === null || options === void 0 ? void 0 : options.groupLabelTemplate;
2757
2801
  const cellRenderer = options === null || options === void 0 ? void 0 : options.groupCellTemplate;
2758
2802
  // setup source
2803
+ this.revogrid.dispatchEvent(new CustomEvent(column_service.BEFORE_GROUPING_APPLY_EVENT));
2759
2804
  this.providers.data.setData(sourceWithGroups, column_service.GROUPING_ROW_TYPE, this.revogrid.disableVirtualY, { depth, customRenderer, cellRenderer }, true);
2805
+ this.remapRowDefinitions(oldNewIndexes !== null && oldNewIndexes !== void 0 ? oldNewIndexes : {}, oldNewIndexMap, currentSource, sourceWithGroups);
2760
2806
  this.updateTrimmed(trimmed, oldNewIndexes !== null && oldNewIndexes !== void 0 ? oldNewIndexes : {}, oldNewIndexMap, sourceWithGroups);
2807
+ if (hasActiveSorting(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sorting)) {
2808
+ sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.reapplySorting();
2809
+ }
2761
2810
  }
2762
2811
  /**
2763
2812
  * Apply grouping on data set
@@ -2766,9 +2815,14 @@ class GroupingRowPlugin extends BasePlugin {
2766
2815
  */
2767
2816
  onDataSet(data) {
2768
2817
  var _a, _b, _c;
2818
+ const currentSource = this.getStore().get('source');
2819
+ const sortingPlugin = this.providers.plugins.getByClass(SortingPlugin);
2820
+ const currentItems = this.isSortingActiveOrPending(sortingPlugin)
2821
+ ? currentSource.map((_, index) => index)
2822
+ : this.getStore().get('proxyItems');
2823
+ const { prevExpanded, oldNewIndexes } = column_service.getSource(currentSource, currentItems, true);
2769
2824
  let preservedExpanded = {};
2770
2825
  if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.preserveGroupingOnUpdate) !== false) {
2771
- let { prevExpanded } = column_service.getSource(this.getStore().get('source'), this.getStore().get('proxyItems'), true);
2772
2826
  preservedExpanded = prevExpanded;
2773
2827
  }
2774
2828
  const source = data.source.filter(s => !column_service.isGrouping(s));
@@ -2780,6 +2834,7 @@ class GroupingRowPlugin extends BasePlugin {
2780
2834
  customRenderer: options.groupLabelTemplate,
2781
2835
  cellRenderer: options.groupCellTemplate,
2782
2836
  });
2837
+ queueMicrotask(() => this.remapRowDefinitions(oldNewIndexes !== null && oldNewIndexes !== void 0 ? oldNewIndexes : {}, oldNewIndexMap, currentSource, sourceWithGroups));
2783
2838
  this.updateTrimmed(trimmed, oldNewIndexMap, undefined, sourceWithGroups, { filterTrimmedMode: 'recompute-after-source-set' });
2784
2839
  }
2785
2840
  /**
@@ -2815,10 +2870,6 @@ class GroupingRowPlugin extends BasePlugin {
2815
2870
  if (!(((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b.length) && ((_c = detail === null || detail === void 0 ? void 0 : detail.source) === null || _c === void 0 ? void 0 : _c.length))) {
2816
2871
  return;
2817
2872
  }
2818
- // if sorting is running don't apply grouping, wait for sorting, then it'll apply in @aftersortingapply
2819
- if (this.isSortingRunning()) {
2820
- return;
2821
- }
2822
2873
  this.onDataSet(detail);
2823
2874
  });
2824
2875
  this.addEventListener('beforecolumnsset', ({ detail }) => {
@@ -2833,17 +2884,6 @@ class GroupingRowPlugin extends BasePlugin {
2833
2884
  this.addEventListener('beforefiltertrimmed', ({ detail }) => {
2834
2885
  detail.itemsToFilter = this.beforeFilterTrimmed(detail.itemsToFilter);
2835
2886
  });
2836
- /**
2837
- * sorting applied need to clear grouping and apply again
2838
- * based on new results whole grouping order will changed
2839
- */
2840
- this.addEventListener('aftersortingapply', () => {
2841
- var _a, _b;
2842
- if (!((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b.length)) {
2843
- return;
2844
- }
2845
- this.doSourceUpdate(this.getCurrentExpandedOptions());
2846
- });
2847
2887
  /**
2848
2888
  * Apply logic for focus inside of grouping
2849
2889
  * We can't focus on grouping rows, navigation only inside of groups for now
@@ -2876,9 +2916,57 @@ class GroupingRowPlugin extends BasePlugin {
2876
2916
  }
2877
2917
  });
2878
2918
  // clear rows
2879
- const { source, oldNewIndexes } = column_service.getSource(this.getStore().get('source'), this.getStore().get('proxyItems'), true);
2919
+ const store = this.getStore();
2920
+ const sortingPlugin = this.providers.plugins.getByClass(SortingPlugin);
2921
+ const currentSource = store.get('source');
2922
+ const sourceItems = this.isSortingActiveOrPending(sortingPlugin)
2923
+ ? currentSource.map((_, index) => index)
2924
+ : store.get('proxyItems');
2925
+ const { source, oldNewIndexes } = column_service.getSource(currentSource, sourceItems, true);
2926
+ this.revogrid.dispatchEvent(new CustomEvent(column_service.BEFORE_GROUPING_APPLY_EVENT));
2880
2927
  this.providers.data.setData(source, column_service.GROUPING_ROW_TYPE, this.revogrid.disableVirtualY, undefined, true);
2928
+ this.remapRowDefinitions(oldNewIndexes !== null && oldNewIndexes !== void 0 ? oldNewIndexes : {}, undefined, currentSource, source);
2881
2929
  this.updateTrimmed(undefined, undefined, oldNewIndexes, source);
2930
+ if (hasActiveSorting(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sorting)) {
2931
+ sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.reapplySorting();
2932
+ }
2933
+ }
2934
+ remapRowDefinitions(firstLevelMap, secondLevelMap, previousSource, nextSource) {
2935
+ const definitions = this.providers.dimension.getRowDefinitions();
2936
+ const nextGroupIndexes = new Map();
2937
+ nextSource === null || nextSource === void 0 ? void 0 : nextSource.forEach((row, index) => {
2938
+ const groupId = row[column_service.PSEUDO_GROUP_ITEM_ID];
2939
+ if (groupId && !nextGroupIndexes.has(groupId)) {
2940
+ nextGroupIndexes.set(groupId, index);
2941
+ }
2942
+ });
2943
+ let changed = false;
2944
+ const remapped = definitions.flatMap(definition => {
2945
+ if (definition.type !== column_service.GROUPING_ROW_TYPE) {
2946
+ return [definition];
2947
+ }
2948
+ const previousRow = previousSource === null || previousSource === void 0 ? void 0 : previousSource[definition.index];
2949
+ const groupId = previousRow === null || previousRow === void 0 ? void 0 : previousRow[column_service.PSEUDO_GROUP_ITEM_ID];
2950
+ const index = groupId
2951
+ ? nextGroupIndexes.get(groupId)
2952
+ : convertGroupingIndex(definition.index, firstLevelMap, secondLevelMap);
2953
+ if (typeof index !== 'number') {
2954
+ changed = true;
2955
+ return [];
2956
+ }
2957
+ if (index < 0) {
2958
+ changed = true;
2959
+ return [];
2960
+ }
2961
+ if (index === definition.index) {
2962
+ return [definition];
2963
+ }
2964
+ changed = true;
2965
+ return [Object.assign(Object.assign({}, definition), { index })];
2966
+ });
2967
+ if (changed) {
2968
+ this.providers.dimension.setRowDefinitions(remapped);
2969
+ }
2882
2970
  }
2883
2971
  updateTrimmed(trimmedGroup = {}, firstLevelMap = {}, secondLevelMap, source = this.getStore().get('source'), { filterTrimmedMode = 'remap', } = {}) {
2884
2972
  // map previously trimmed data
@@ -3219,18 +3307,14 @@ const ROW_RESIZE_EVENT = 'rowresize';
3219
3307
  const AFTER_ROW_RESIZE_EVENT = 'afterrowresize';
3220
3308
  const ROW_RESIZE_CANCEL_EVENT = 'rowresizecancel';
3221
3309
  class RowResizePlugin extends BasePlugin {
3222
- static fromGridProperty(revogrid, providers) {
3223
- const plugin = new RowResizePlugin(revogrid, providers);
3224
- plugin.controlFromGridProperty();
3225
- return plugin;
3226
- }
3227
3310
  constructor(revogrid, providers, config = {}) {
3228
3311
  super(revogrid, providers);
3229
3312
  this.enabled = false;
3230
- this.gridResizeRow = false;
3231
- this.gridPlugins = [];
3232
- this.committedSizes = new Map();
3233
- this.appliedIndexes = new Map();
3313
+ this.appliedDefinitionIndexes = new Map();
3314
+ this.pendingBottomAnchor = false;
3315
+ this.keepBottomAnchor = false;
3316
+ this.rowDefinitionRemapQueued = false;
3317
+ this.pendingSourceCounts = new Map();
3234
3318
  this.previousBodyCursor = '';
3235
3319
  this.decorateRow = ({ detail, }) => {
3236
3320
  if (!this.enabled ||
@@ -3294,22 +3378,72 @@ class RowResizePlugin extends BasePlugin {
3294
3378
  }
3295
3379
  };
3296
3380
  this.onWindowBlur = () => this.cancel('blur');
3297
- this.reapplyCommittedSizes = () => this.applyCommittedSizes(false);
3298
- this.rebuildCommittedSizes = () => this.applyCommittedSizes(true);
3299
- this.syncAppliedIndexes = () => {
3300
- for (const [rowType, committed] of this.committedSizes) {
3381
+ this.updateBottomAnchorState = ({ detail, }) => {
3382
+ if (detail.dimension !== 'rgRow') {
3383
+ return;
3384
+ }
3385
+ this.keepBottomAnchor = this.isMainViewportAtBottom(detail.coordinate);
3386
+ };
3387
+ this.applyPendingBottomAnchor = () => {
3388
+ if (!this.pendingBottomAnchor) {
3389
+ return;
3390
+ }
3391
+ this.pendingBottomAnchor = false;
3392
+ const dimension = this.providers.dimension.stores.rgRow.store;
3393
+ // Scroll surfaces have slightly different client sizes. Give the shared
3394
+ // scrolling service the content end and let each surface clamp to its own
3395
+ // exact bottom coordinate.
3396
+ void this.revogrid.scrollToCoordinate({ y: dimension.get('realSize') });
3397
+ };
3398
+ this.scheduleRowDefinitionRemap = () => {
3399
+ if (this.rowDefinitionRemapQueued) {
3400
+ return;
3401
+ }
3402
+ this.rowDefinitionRemapQueued = true;
3403
+ queueMicrotask(() => {
3404
+ if (!this.rowDefinitionRemapQueued) {
3405
+ return;
3406
+ }
3407
+ this.pruneRowDefinitions();
3408
+ this.reapplyRowDefinitionSizes();
3409
+ this.rowDefinitionRemapQueued = false;
3410
+ });
3411
+ };
3412
+ /** Map source-indexed row definitions back onto the current virtual order. */
3413
+ this.reapplyRowDefinitionSizes = () => {
3414
+ const rowDefinitions = this.providers.dimension.getRowDefinitions();
3415
+ for (const rowType of column_service.rowTypes) {
3301
3416
  const items = this.providers.data.stores[rowType].store.get('items');
3417
+ const definitions = new Map(rowDefinitions
3418
+ .filter(definition => definition.type === rowType)
3419
+ .map(definition => [definition.index, definition.size]));
3420
+ const appliedIndexes = this.appliedDefinitionIndexes.get(rowType);
3421
+ if (!definitions.size && !(appliedIndexes === null || appliedIndexes === void 0 ? void 0 : appliedIndexes.size)) {
3422
+ continue;
3423
+ }
3424
+ const dimension = this.providers.dimension.stores[rowType];
3425
+ const currentSizes = dimension.store.get('sizes');
3426
+ const sizes = Object.assign({}, currentSizes);
3427
+ for (const index of appliedIndexes || []) {
3428
+ delete sizes[index];
3429
+ }
3302
3430
  const indexes = new Set();
3303
3431
  items.forEach((physicalIndex, virtualIndex) => {
3304
- if (committed.has(physicalIndex)) {
3432
+ const size = definitions.get(physicalIndex);
3433
+ if (size !== undefined) {
3434
+ sizes[virtualIndex] = size;
3305
3435
  indexes.add(virtualIndex);
3306
3436
  }
3307
3437
  });
3308
- this.appliedIndexes.set(rowType, indexes);
3438
+ this.appliedDefinitionIndexes.set(rowType, indexes);
3439
+ const sizeKeys = Object.keys(sizes);
3440
+ if (sizeKeys.length !== Object.keys(currentSizes).length ||
3441
+ sizeKeys.some(index => sizes[index] !== currentSizes[index])) {
3442
+ this.providers.dimension.setCustomSizes(rowType, sizes);
3443
+ }
3309
3444
  }
3310
3445
  };
3311
3446
  this.config = resolveRowResizeConfig(config);
3312
- this.rowDefinitionsRef = revogrid.rowDefinitions;
3313
3447
  if (new.target !== RowResizePlugin) {
3314
3448
  this.enabled = true;
3315
3449
  this.registerEventListeners();
@@ -3317,77 +3451,53 @@ class RowResizePlugin extends BasePlugin {
3317
3451
  }
3318
3452
  registerEventListeners() {
3319
3453
  this.addEventListener('beforerowrender', this.decorateRow);
3320
- this.addEventListener('beforeanysource', ({ detail }) => {
3454
+ this.addEventListener('beforeanysource', () => {
3321
3455
  this.cancel('data-change');
3322
- const committed = this.committedSizes.get(detail.type);
3323
- if (!committed) {
3324
- return;
3325
- }
3326
- const removedIndexes = new Set();
3327
- for (const index of committed.keys()) {
3328
- if (index >= detail.source.length) {
3329
- committed.delete(index);
3330
- removedIndexes.add(index);
3331
- }
3332
- }
3333
- if (removedIndexes.size) {
3334
- const rowDefinitions = this.revogrid.rowDefinitions.filter(definition => definition.type !== detail.type ||
3335
- !removedIndexes.has(definition.index));
3336
- this.rowDefinitionsRef = rowDefinitions;
3337
- this.revogrid.rowDefinitions = rowDefinitions;
3338
- }
3456
+ this.keepBottomAnchor = false;
3457
+ });
3458
+ this.addEventListener('afteranysource', ({ detail }) => {
3459
+ this.pendingSourceCounts.set(detail.type, detail.source.length);
3460
+ this.scheduleRowDefinitionRemap();
3339
3461
  });
3340
- this.addEventListener('afteranysource', this.rebuildCommittedSizes);
3341
3462
  this.addEventListener('beforesourcesortingapply', this.cancelForDataChange);
3342
- this.addEventListener('aftersortingapply', this.reapplyCommittedSizes);
3463
+ this.addEventListener('beforesortingapply', this.cancelForDataChange);
3464
+ this.addEventListener('sortingconfigchanged', this.cancelForDataChange);
3465
+ this.addEventListener(column_service.BEFORE_GROUPING_APPLY_EVENT, this.cancelForDataChange);
3466
+ this.addEventListener('aftersortingapply', this.scheduleRowDefinitionRemap);
3343
3467
  this.addEventListener('beforefilterapply', this.cancelForDataChange);
3344
- this.addEventListener('beforerowdefinition', ({ detail }) => {
3468
+ this.addEventListener('afterfilterapply', this.scheduleRowDefinitionRemap);
3469
+ this.addEventListener('beforerowdefinition', () => {
3345
3470
  this.cancel('data-change');
3346
- if (detail.vals !== this.rowDefinitionsRef) {
3347
- this.committedSizes.clear();
3348
- this.appliedIndexes.clear();
3349
- this.rowDefinitionsRef = detail.vals;
3350
- }
3351
- });
3352
- this.addEventListener('afterthemechanged', this.reapplyCommittedSizes);
3353
- this.addEventListener('aftertrimmed', this.syncAppliedIndexes);
3354
- this.addEventListener('roworderchange', () => {
3355
- queueMicrotask(this.reapplyCommittedSizes);
3471
+ this.scheduleRowDefinitionRemap();
3356
3472
  });
3473
+ this.addEventListener('afterthemechanged', this.scheduleRowDefinitionRemap);
3474
+ this.addEventListener('aftertrimmed', this.scheduleRowDefinitionRemap);
3475
+ this.addEventListener('roworderchange', this.scheduleRowDefinitionRemap);
3357
3476
  this.addEventListener(column_service.GROUP_EXPAND_EVENT, () => {
3358
- queueMicrotask(this.reapplyCommittedSizes);
3477
+ if (this.keepBottomAnchor) {
3478
+ this.pendingBottomAnchor = true;
3479
+ }
3480
+ this.scheduleRowDefinitionRemap();
3359
3481
  });
3482
+ this.addEventListener('aftergridrender', this.applyPendingBottomAnchor);
3483
+ this.addEventListener('viewportscroll', this.updateBottomAnchorState);
3360
3484
  this.addEventListener('rowheaderschanged', ({ detail }) => {
3361
3485
  if (!detail && !this.config.fullRow) {
3362
3486
  this.cancel('row-headers-hidden');
3363
3487
  }
3364
3488
  });
3365
3489
  }
3366
- controlFromGridProperty() {
3367
- this.gridResizeRow = this.revogrid.resizeRow;
3368
- this.gridPlugins = this.revogrid.plugins;
3369
- this.syncGridProperty(false);
3370
- this.watch('resizeRow', value => {
3371
- this.gridResizeRow = value;
3372
- this.syncGridProperty();
3373
- });
3374
- this.watch('plugins', value => {
3375
- this.gridPlugins = value || [];
3376
- this.syncGridProperty();
3377
- });
3378
- }
3379
- syncGridProperty(refresh = true) {
3380
- const hasConfiguredPlugin = this.gridPlugins.some(plugin => plugin !== RowResizePlugin &&
3490
+ syncGridConfig(refresh = true) {
3491
+ const { plugins = [], resizeRow } = this.revogrid;
3492
+ const isCorePlugin = this.constructor === RowResizePlugin;
3493
+ const hasConfiguredPlugin = plugins.some(plugin => plugin !== RowResizePlugin &&
3381
3494
  plugin.prototype instanceof RowResizePlugin);
3382
- const explicitlyEnabled = this.gridPlugins.includes(RowResizePlugin);
3383
- const enabled = hasConfiguredPlugin
3384
- ? false
3385
- : explicitlyEnabled || !!this.gridResizeRow;
3386
- const config = resolveRowResizeConfig(!hasConfiguredPlugin &&
3387
- !explicitlyEnabled &&
3388
- typeof this.gridResizeRow === 'object'
3389
- ? this.gridResizeRow
3390
- : undefined);
3495
+ const enabled = !isCorePlugin ||
3496
+ (!hasConfiguredPlugin && !!resizeRow);
3497
+ const resizeConfig = typeof resizeRow === 'object' ? resizeRow : undefined;
3498
+ const config = isCorePlugin
3499
+ ? resolveRowResizeConfig(resizeConfig)
3500
+ : this.config;
3391
3501
  const configChanged = config.minHeight !== this.config.minHeight ||
3392
3502
  config.maxHeight !== this.config.maxHeight ||
3393
3503
  config.fullRow !== this.config.fullRow;
@@ -3399,10 +3509,13 @@ class RowResizePlugin extends BasePlugin {
3399
3509
  if (enabled !== this.enabled) {
3400
3510
  this.enabled = enabled;
3401
3511
  if (enabled) {
3402
- this.rowDefinitionsRef = this.revogrid.rowDefinitions;
3403
3512
  this.registerEventListeners();
3404
3513
  }
3405
3514
  else {
3515
+ this.pendingBottomAnchor = false;
3516
+ this.keepBottomAnchor = false;
3517
+ this.rowDefinitionRemapQueued = false;
3518
+ this.pendingSourceCounts.clear();
3406
3519
  this.clearSubscriptions();
3407
3520
  }
3408
3521
  }
@@ -3421,6 +3534,7 @@ class RowResizePlugin extends BasePlugin {
3421
3534
  }
3422
3535
  const dimension = this.providers.dimension.stores[rowType];
3423
3536
  const dimensionState = dimension.getCurrentState();
3537
+ const viewport = this.providers.viewport.stores[rowType];
3424
3538
  const item = dimension_helpers.getItemByIndex(dimensionState, index);
3425
3539
  const focusedStore = this.providers.selection.focusedStore;
3426
3540
  const selectedRowType = focusedStore
@@ -3452,16 +3566,23 @@ class RowResizePlugin extends BasePlugin {
3452
3566
  currentHeight: startHeight,
3453
3567
  previousSizes,
3454
3568
  originalCustomSizes: Object.assign({}, dimensionState.sizes),
3455
- startEvent: event,
3569
+ bottomAnchored: rowType === 'rgRow' &&
3570
+ this.isMainViewportAtBottom(viewport.lastCoordinate),
3456
3571
  lastEvent: event,
3457
3572
  };
3573
+ this.active = active;
3458
3574
  const beforeEvent = this.emit(BEFORE_ROW_RESIZE_EVENT, this.eventDetail(active, event, startHeight));
3459
3575
  if (beforeEvent.defaultPrevented) {
3576
+ if (this.active === active) {
3577
+ this.active = undefined;
3578
+ }
3579
+ return;
3580
+ }
3581
+ if (!this.enabled || this.active !== active) {
3460
3582
  return;
3461
3583
  }
3462
3584
  event.preventDefault();
3463
3585
  event.stopPropagation();
3464
- this.active = active;
3465
3586
  const doc = this.revogrid.ownerDocument;
3466
3587
  this.previousBodyCursor = ((_a = doc.body) === null || _a === void 0 ? void 0 : _a.style.cursor) || '';
3467
3588
  if (doc.body) {
@@ -3484,6 +3605,7 @@ class RowResizePlugin extends BasePlugin {
3484
3605
  return;
3485
3606
  }
3486
3607
  this.providers.dimension.setCustomSizes(active.rowType, createRowResizePatch(active.indexes, size), true);
3608
+ this.requestBottomAnchor(active);
3487
3609
  active.currentHeight = size;
3488
3610
  this.emit(ROW_RESIZE_EVENT, this.eventDetail(active, active.lastEvent, size));
3489
3611
  }
@@ -3502,7 +3624,8 @@ class RowResizePlugin extends BasePlugin {
3502
3624
  }
3503
3625
  }
3504
3626
  this.providers.dimension.setCustomSizes(active.rowType, currentSizes);
3505
- const detail = Object.assign(Object.assign({}, this.eventDetail(active, active.lastEvent || active.startEvent, active.startHeight)), { reason });
3627
+ this.requestBottomAnchor(active);
3628
+ const detail = Object.assign(Object.assign({}, this.eventDetail(active, active.lastEvent, active.startHeight)), { reason });
3506
3629
  this.finishGesture();
3507
3630
  this.emit(ROW_RESIZE_CANCEL_EVENT, detail);
3508
3631
  }
@@ -3521,51 +3644,44 @@ class RowResizePlugin extends BasePlugin {
3521
3644
  return;
3522
3645
  }
3523
3646
  const items = this.providers.data.stores[active.rowType].store.get('items');
3524
- let committed = this.committedSizes.get(active.rowType);
3525
- if (!committed) {
3526
- committed = new Map();
3527
- this.committedSizes.set(active.rowType, committed);
3528
- }
3529
- let applied = this.appliedIndexes.get(active.rowType);
3530
- if (!applied) {
3531
- applied = new Set();
3532
- this.appliedIndexes.set(active.rowType, applied);
3533
- }
3534
3647
  const physicalIndexes = active.indexes.reduce((result, index) => {
3535
3648
  const physicalIndex = items[index];
3536
3649
  if (physicalIndex !== undefined) {
3537
- committed.set(physicalIndex, active.currentHeight);
3538
- applied.add(index);
3539
3650
  result.push(physicalIndex);
3540
3651
  }
3541
3652
  return result;
3542
3653
  }, []);
3543
3654
  if (physicalIndexes.length) {
3544
- const rowDefinitions = mergeRowResizeDefinitions(this.revogrid.rowDefinitions, active.rowType, physicalIndexes, active.currentHeight);
3545
- this.rowDefinitionsRef = rowDefinitions;
3546
- this.revogrid.rowDefinitions = rowDefinitions;
3655
+ const rowDefinitions = mergeRowResizeDefinitions(this.providers.dimension.getRowDefinitions(), active.rowType, physicalIndexes, active.currentHeight);
3656
+ this.providers.dimension.setRowDefinitions(rowDefinitions);
3657
+ this.scheduleRowDefinitionRemap();
3658
+ this.keepBottomAnchor = active.bottomAnchored;
3659
+ this.requestBottomAnchor(active);
3547
3660
  }
3548
3661
  }
3549
- applyCommittedSizes(clearAppliedIndexes) {
3550
- for (const [rowType, committed] of this.committedSizes) {
3551
- const dimension = this.providers.dimension.stores[rowType];
3552
- const sizes = Object.assign({}, dimension.store.get('sizes'));
3553
- if (clearAppliedIndexes) {
3554
- for (const index of this.appliedIndexes.get(rowType) || []) {
3555
- delete sizes[index];
3556
- }
3557
- }
3558
- const items = this.providers.data.stores[rowType].store.get('items');
3559
- const indexes = new Set();
3560
- items.forEach((physicalIndex, virtualIndex) => {
3561
- const size = committed.get(physicalIndex);
3562
- if (size !== undefined) {
3563
- sizes[virtualIndex] = size;
3564
- indexes.add(virtualIndex);
3565
- }
3566
- });
3567
- this.appliedIndexes.set(rowType, indexes);
3568
- this.providers.dimension.setCustomSizes(rowType, sizes);
3662
+ requestBottomAnchor(active) {
3663
+ if (active.bottomAnchored) {
3664
+ this.pendingBottomAnchor = true;
3665
+ }
3666
+ }
3667
+ isMainViewportAtBottom(coordinate) {
3668
+ const dimension = this.providers.dimension.stores.rgRow.getCurrentState();
3669
+ const viewport = this.providers.viewport.stores.rgRow.store.state;
3670
+ return (dimension.realSize > viewport.clientSize &&
3671
+ coordinate >= viewport_store.getViewportMaxCoordinate(dimension, viewport.virtualSize));
3672
+ }
3673
+ pruneRowDefinitions() {
3674
+ if (!this.pendingSourceCounts.size) {
3675
+ return;
3676
+ }
3677
+ const definitions = this.providers.dimension.getRowDefinitions();
3678
+ const rowDefinitions = definitions.filter(definition => {
3679
+ const count = this.pendingSourceCounts.get(definition.type);
3680
+ return count === undefined || definition.index < count;
3681
+ });
3682
+ this.pendingSourceCounts.clear();
3683
+ if (rowDefinitions.length !== definitions.length) {
3684
+ this.providers.dimension.setRowDefinitions(rowDefinitions);
3569
3685
  }
3570
3686
  }
3571
3687
  finishGesture() {
@@ -3588,6 +3704,9 @@ class RowResizePlugin extends BasePlugin {
3588
3704
  }
3589
3705
  destroy() {
3590
3706
  this.cancel('destroy');
3707
+ this.keepBottomAnchor = false;
3708
+ this.rowDefinitionRemapQueued = false;
3709
+ this.pendingSourceCounts.clear();
3591
3710
  super.destroy();
3592
3711
  }
3593
3712
  }